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