Jump to content

Callback from another thread.


Recommended Posts

I'm having troubles with having a custom made dll call callbacks to my au3 script. The thing that makes this error prone is that the dll calls the autoit callback from a new thread.

To illustrate the problem I'm having I made the following sources.

Dll source:

#include <windows.h>

typedef void CALLBACK AUTOITCALLBACK(int);

DWORD WINAPI DoSomething(void* param)
{
    AUTOITCALLBACK *callback=((AUTOITCALLBACK*)param);
    Sleep(500); // Do something that takes a while..
    callback(1337);
    return 0;
}


extern "C" __declspec(dllexport) void asyncjob(AUTOITCALLBACK *callback)
{
    CreateThread(NULL,0,DoSomething,(void*)callback,0,NULL);
    Sleep(25); // Gives the thread time to copy the callback ptr
}

Au3 source:

Global $runloop=True
$cb=DllCallbackRegister("f","none","int")

$dll=DllOpen("testbug.dll")

DllCall($dll,"none:cdecl","asyncjob","ptr",DllCallbackGetPtr($cb))


While $runloop; Never quits
    Sleep(10)
WEnd


Func f($x)
    MsgBox(0,"",$x); Works ok.
    box(); Doesn't execute
    $runloop=false; Fails to change $runloop
EndFunc

func box()
    MsgBox(0,"","")
EndFu

I'm guessing this have to do with autoit not being thread safe, and if that's the case how should I solve my problem?

Thanks.

Edited by monoceres

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

So to summarize the whole thing, why can't I modify variables and call user defined functions when a callback is running in the context of a different thread? Reading variables and calling built in functions works as expected.

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

I think you're making a deadlock of some sort ;] can't be sure. This for example return correctly and the script exits eventually. I know it's not sane to compute how much time the called function requires...

Global $runloop=True
$cb=DllCallbackRegister("f","none","int")

$dll=DllOpen("test.dll")

DllCall($dll,"none:cdecl","asyncjob","ptr",DllCallbackGetPtr($cb))


While $runloop; Never quits
    Sleep(10)
WEnd


Func f($x)
    MsgBox(0, '', $x)
    ;ConsoleWrite($x & @LF); Works ok.
    ;box(); Doesn't execute
    $runloop=false; Fails to change $runloop
EndFunc

func box()
    MsgBox(0, '', '')
    ;ConsoleWrite('Data' & @LF)
EndFuncoÝ÷ Ø«zZr)ànZ)àq©e³*.®Ç+{,-¡×¢Énuî´Â)Ý£!ëh§r[{­-r«­­ÊyûèÐ,°@ LâËãH§·CXäCX@

#include <windows.h>
#include <tchar.h>

typedef void CALLBACK AUTOITCALLBACK(int);

DWORD WINAPI DoSomething(void* param)
{
    AUTOITCALLBACK *callback=((AUTOITCALLBACK*)param);
    HANDLE hSemaphore = CreateSemaphore(NULL, 1, 1, _T("Semama"));
    Sleep(500); // Do something that takes a while..
    callback(1337);
    WaitForSingleObject(hSemaphore, INFINITE);
    CloseHandle(hSemaphore);
    MessageBox(NULL, _T("Text"), _T("Title"), MB_OK | MB_ICONINFORMATION);
    ExitThread(0);
}


extern "C" __declspec(dllexport) void asyncjob(AUTOITCALLBACK *callback)
{
    CreateThread(NULL,0,DoSomething,(void*)callback,0,NULL);
    Sleep(50); // Gives the thread time to copy the callback ptr
}
Link to comment
Share on other sites

What happens if you don't use MsgBox()? What about using ConsoleWrite()? Please try the original DLL from the first post as well as the original code except replace the MsgBox() calls with ConsoleWrite(). The synchronization code should not be necessary.

Edit: It's important that you use ConsoleWrite() and not something else because I know the code execution path for that particular function.

Edited by Valik
Link to comment
Share on other sites

Very interesting, it's indeed working fine without the MsgBox() calls. Any ideas why MsgBox makes the callback stop executing and more important, what other functions will produce the same freeze? Is this perhaps linked with the fact that autoit creates an extra thread for the call to MessageBox?

Broken link? PM me and I'll send you the file!

Link to comment
Share on other sites

Simple way to test: Try InetGet(). It creates another thread to do the download. However, I suspect it's something else. I'm trying to remember the circumstances but I've dead-locked stuff before by using a GUI (probably MessageBox()) too early before. I can't remember the exact circumstances, though.

Link to comment
Share on other sites

Don't know if you mind but even without blocking functions or popping up a GUI you can easily lock the script. Consider this for example, you can change it with a sleep(500) call or other time consuming function execution:

#include <Array.au3>

Global $runloop=True
Global $avArray[3] = ['1', '2', '3']
$cb=DllCallbackRegister("f","none","int")

$dll=DllOpen("test.dll")

DllCall($dll,"none:cdecl","asyncjob","ptr",DllCallbackGetPtr($cb))


While $runloop; Never quits
    Sleep(10)
WEnd


Func f($x)
    Local $j = 0
    For $i = 1 To 0x10000
        $j = $i*BitXOR($i, $j); Works ok.
    Next
    
    $runloop=false; Fails to change $runloop
EndFunc

It still locks the entire script somewhere in the For..Next loop. So you can't say that ConsoleWrite will solve the case. It's an asynchronous case here. Correct me where I'm wrong.

Edited by Authenticity
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...