digitalmars.D.learn - Runtime error when calling a callback in a parallel Task
- BBasile (32/32) Sep 15 2015 Under Windows this works fine but under Linux I got a runtime
- BBasile (4/8) Sep 16 2015 If it can help to understand the problem, here is the unreducted
- =?UTF-8?Q?Ali_=c3=87ehreli?= (38/39) Sep 16 2015 Can it be because 'param' is invalid at the time clbck is called? The
- BBasile (8/15) Sep 16 2015 No the callback and its user parameter are set at the same time.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (11/24) Sep 16 2015 I don't want to sound like insisting on my idea but I was more concerned...
Under Windows this works fine but under Linux I got a runtime error. this could be reduced to : --- import std.parallelism; alias CallBack = void function(void*); class Foo { CallBack clbck; void* param; void dotask() { // some heavy processing // tells the caller that some fresh data are available if(clbck) clbck(param); // debugger breaks HERE } void call() { task(&dotask).executeInNewThread; // returns directly but the caller will get a notif when finished } } --- more info about the environment: - linux i386 - the D program is actually a .so and the main thread is the exe that loads this .so. - If i don't use a Task then the program works **fine**. Is it possible to achieve this in a cross platform-way ? How can i get in phase with the main big thread at the end of my task ?
Sep 15 2015
On Tuesday, 15 September 2015 at 23:49:23 UTC, BBasile wrote:Under Windows this works fine but under Linux I got a runtime error. this could be reduced to : [...]If it can help to understand the problem, here is the unreducted case: https://github.com/BBasile/Coedit/blob/master/cedast/src/ast.d#L343
Sep 16 2015
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? The following program works under Linux. However, removing thread_joinAll() is a bug: import std.parallelism; import std.stdio; alias CallBack = void function(void*); class Foo { CallBack clbck; void* param; void dotask() { // some heavy processing // tells the caller that some fresh data are available if(clbck) clbck(param); // debugger breaks HERE } void call() { task(&dotask).executeInNewThread; // returns directly but the caller will get a notif when finished } } void handler(void* p) { writefln("Finishing with %s at %s", *(cast(int*)p), p); } void main() { auto foo = new Foo(); foo.clbck = &handler; int i = 42; foo.param = &i; foo.call(); import core.thread; thread_joinAll(); } Ali
Sep 16 2015
On Wednesday, 16 September 2015 at 18:19:07 UTC, Ali Çehreli wrote:On 09/15/2015 04:49 PM, BBasile wrote:No the callback and its user parameter are set at the same time.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?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. :/
Sep 16 2015
On 09/16/2015 02:01 PM, BBasile wrote:On Wednesday, 16 September 2015 at 18:19:07 UTC, Ali Çehreli wrote: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.On 09/15/2015 04:49 PM, BBasile wrote:No the callback and its user parameter are set at the same time.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?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. AliThe 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. :/
Sep 16 2015
On Wednesday, 16 September 2015 at 22:30:26 UTC, Ali Çehreli wrote:On 09/16/2015 02:01 PM, BBasile wrote:No, the param is fine. As said initially:On Wednesday, 16 September 2015 at 18:19:07 UTC, Ali Çehreliwrote:runtime error.On 09/15/2015 04:49 PM, BBasile wrote:Under Windows this works fine but under Linux I got acalled?Can it be because 'param' is invalid at the time clbck isNo the callback and its user parameter are set at the sametime. 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.`thread_joinAll` thatThe 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 callsimply. Maybe as an additonal dll export but in this case if `thread_joinAll` does something with the Runtime (?) it'squite probablethat 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. AliIf 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.
Sep 16 2015
Maybe compiler generates wrong code, try to debug at instruction level.
Sep 17 2015