zaqimon

Possible reentrance behavior and solution

2 posts in this topic

#1 ·  Posted (edited)

 

GUICtrlSendToDummy() fails to work when GUISetState(@SW_HIDE)

I also tried SendMessage, PostMessage without luck. While one message being processed, another same message will just be dropped.

Finally I choose Mailslot mechanism to serialize function execution without reentrance. Though if your GUI will never hide, you can count on GUICtrlSendToDummy() without problem.

 

+++ ORIGINAL POST BELOW +++

I know AutoIt runs in single thread. But I found function execution (e.g. a button click) will be interrupted halfway by Adlib/Timer functions. I think I can use reference counter on function entry/exit to ensure my function execution won't be interrupted by Adlib/Timer functions. For example, if reference counter greater than 0, then Adlib/Timer function will return immediately. And here are my two questions.

1. Is there any better option than reference counting to ensure non-interrupted function execution?

2. Is there any major difference to choose between Adlib or SetTimer functions?

Thanks.

 

Answer my own question. Using GUICtrlSendToDummy() to serialize Adlib events without interrupting execution of other functions.

 

Here is my example script to demonstrate this behavior. If you set $USE_DUMMY = False, you might have reentrance-like behavior within BusyFunc(), which may cause unexpected result of your code if they are accessing the same data. Use GUICtrlSendToDummy() solve this problem. I think this is by design AutoIt behavior for not freezing the whole GUI interaction with badly written scripts, but this kind of reentrace-like behavior might cause problems sometimes. I guess not only Adlib but all external events will incur this kind of behavior. I don't know how many AutoIt users experience this kind of behavior. I didn't expect this kind of behavior to happen in the first place because I thought AutoIt is a single-threaded script.

Const $USE_DUMMY = False

#include <GUIConstantsEx.au3>

$hGUI = GUICreate("Function Execution", 300, 200)
$btn_test1 = GUICtrlCreateButton("test1", 10, 10, 85, 25)
If $USE_DUMMY Then
    $dummy1 = GUICtrlCreateDummy()
EndIf
GUISetState(@SW_SHOW, $hGUI)

AdlibRegister("_adlib1",1000)

While 1
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then
        ExitLoop
    ElseIf $msg = $btn_test1 Then
        BusyFunc("test1")
    ElseIf $USE_DUMMY Then
        If $msg = $dummy1 Then
            BusyFunc("dummy1")
        EndIf
    EndIf
WEnd

GUIDelete($hGUI)


; ====================================================


Func BusyFunc($from) ; simulate busy function
    ConsoleWrite("++++++++++ "&$from&@CRLF)
    Sleep(100)
    ConsoleWrite("1 "&$from&@CRLF)
    Sleep(100)
    ConsoleWrite("2 "&$from&@CRLF)
    Sleep(100)
    ConsoleWrite("3 "&$from&@CRLF)
    Sleep(100)
    ConsoleWrite("4 "&$from&@CRLF)
    Sleep(100)
    ConsoleWrite("---------- "&$from&@CRLF)
EndFunc


Func _adlib1()
    If $USE_DUMMY Then
        GUICtrlSendToDummy($dummy1) ; call indirectly, serialize all external event, no reentrance
    Else
        BusyFunc("adlib1") ; call directly, reentrance-like behavior may occur
    Endif
EndFunc

 

The output may look like

++++++++++ test1
1 test1
2 test1
++++++++++ adlib1
1 adlib1
2 adlib1
3 adlib1
4 adlib1
---------- adlib1
3 test1
4 test1
---------- test1

 

Edited by zaqimon

Share this post


Link to post
Share on other sites



You should post code to go with questions.  Sometimes the answer you think you need is not the answer best to give.

An example would be your script is running some sort of installer and you want your adlib function to not interrupt that installer.

You could write your actual function to something like this.

AdlibRegister("TestFunc", 1000)

TestFunc()
If ProcessExists("Installer.exe") Then RETURN
;Stuff to do if Installer.exe is not currently running
EndFunc

Runnable code: If AdlibRegister was to run every 1000ms you would get a TON of notepad instances :)

AdlibRegister("KeepNotepadAlive", 1000)

HotKeySet("{ESC}", "Terminate")

While 1
    Sleep(10)
WEnd

Func KeepNotepadAlive()
    If ProcessExists("Notepad.exe") Then Return
    Run("Notepad.exe")
EndFunc

Func Terminate()
    Exit
EndFunc

 

Share this post


Link to post
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