Runtime error when calling a callback in a parallel Task
BBasile via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Wed Sep 16 17:50:16 PDT 2015
On Wednesday, 16 September 2015 at 22:30:26 UTC, Ali Çehreli
wrote:
> On 09/16/2015 02:01 PM, BBasile wrote:
> > On Wednesday, 16 September 2015 at 18:19:07 UTC, Ali Çehreli
> wrote:
> >> On 09/15/2015 04:49 PM, BBasile wrote:
> >>> Under Windows this works fine but under Linux I got a
> runtime error.
> >>
> >> Can it be because 'param' is invalid at the time clbck is
> called?
> >
> > No the callback and its user parameter are set at the same
> time.
>
> I don't want to sound like insisting on my idea but I was more
> concerned about the time when param's life ended. The callback
> is just a function pointer. Functions never die, so there is no
> concern with that. However, the actual variable that 'param' is
> pointing at may have been gone before the callback is executed.
>
> >> The following program works under Linux. However, removing
> >> thread_joinAll() is a bug:
> >
> > I got to try `thread_joinAll`.
> >
> > The main thread is not a D program so i cant call
> `thread_joinAll` that
> > simply. Maybe as an additonal dll export but in this case if
> > `thread_joinAll` does something with the Runtime (?) it's
> quite probable
> > that it won't have an effect. :/
>
> In my code, thread_joinAll() simply made main() wait until the
> thread finished. Otherwise, if main() ended before the thread,
> the int data would be invalid when the callback was using a
> pointer to its (old) location.
>
> Ali
No, the param is fine. As said initially:
> If i don't use a Task then the program works **fine**.
There is a synchronization problem and only under Linux.
Here is a small program that illustrates better the pattern
(based on your previous sample):
---
import std.parallelism;
alias CallBack = void function(void*);
class Foreground
{
private Background back;
bool dataAvailable;
this()
{
back = new Background;
back.clbck = &backgroundFinished;
back.param = cast(void*) this;
}
public void something()
{
dataAvailable = false;
back.call;
}
private static void backgroundFinished(void* param)
{
with (cast(Foreground) param) dataAvailable = true;
}
// lock the access until the background thread notifies that
// interestingData is ready.
Background access()
{
if (dataAvailable)
return back;
else
return null;
}
}
class Background
{
CallBack clbck;
void* param;
private void dotask()
{
// processing on interestingData
if(clbck) clbck(param); // debugger breaks HERE
}
void call()
{
task(&dotask).executeInNewThread;
}
public uint interestingData;
}
void main()
{
auto fore = new Foreground();
import std.random;
while (true) // you'll have to kill by hand !
{
// maybe access will be locked
if (uniform(0,100) > 95)
fore.something;
// try to see if access is readable
if (uniform(0,100) > 20)
if (fore.access) {/*can use fore.access.interesting
data*/}
}
}
---
a class 'A' operating in the main thread is linked to a
background class 'B' that makes some threaded updates. Other
classes operating in the main thread can also have an access to
the backgound class B but only through 'A' and if 'A' doesn't
lock the access. The access is locked when 'B' is updating in a
Thread and until 'B' notifies 'A' that the data are ready.
I use a notification because I'm afraid of the results that other
classes could get when exploiting the 'B' interstingData. They
only **read** them.
More information about the Digitalmars-d-learn
mailing list