Prevent simultaneous execution of code by multiple threads

Syntax1 - lock

lock [name] [mutex] [timeoutMS]

 

Syntax2 - unlock

lock- [name]

 

Parameters

name - name of this lock. Must be like a variable name, without quotes. Used to identify the same lock in multiple functions (or macros, etc). Can be omitted or literal 0 if this lock is used only in current function.

mutex - mutex name. String. Case sensitive. Can contain any characters except \. Can have "Global\" or "Local\" prefix. Read more in remarks.

timeoutMS - max time (milliseconds) to wait in case another thread is executing locked code. Integer. On timeout throws error that can be handled by err. If omitted or -1, waits infinitely. To just check whether the code is locked, use 0.

 

Options:

- unlock.

 

Remarks

Added in QM 2.2.0.

 

A thread is a running function or macro. Multiple threads can run simultaneously. It means that two or more threads can execute the same code block at the same time. Sometimes it is important to prevent this. For example, if one thread is writing to a file (e.g. using str.setfile), another thread would fail to open the file at that time. Or, if one thread is modifying a global variable, the value of the variable may become incorrect if another thread also modifies it at the same time. Use lock to avoid this.

 

Syntax1

Locks the following block of code (code from lock to lock- or to the end of the function). It means that the code cannot be executed by more than one thread at a time. If thread2 wants to execute the code while thread1 is executing it, thread2 waits until thread1 finishes executing the code.

 

Syntax2

Unlocks the code block that was locked by lock. Unlocking in many cases is not necessary. QM automatically unlocks the code when the function exits.

 

If name was used with lock, use the same name with lock-.

 

lock- unlocks the code only if lock- was actually executed. For example, if you goto somewhere without executing lock-, the code remains locked.

 

------

 

You can use the same named lock (the same name) in multiple functions. For example, while one thread is executing locked code in function1, other threads also will not be able to execute locked code in function2 if the code is locked with the same named lock.

 

Don't use multiple lock without lock-. The lock count is incremented (by 1) by lock and decremented (by 1) by lock- and when the function exits. If the lock count is more than 1 when the function exits, all code locked by that lock object remains locked. To reset, you can execute lock- somewhere else, or restart QM.

 

Be careful using lock. Two threads can lock each other, causing both to wait forever. Example: Thread1 is executing locked code and sends message to a window of thread2. Thread2 receives the message and tries to execute the same code (or other code locked by the same named lock). Result: Thread1 waits in SendMessage (because thread2 waits in lock), and thread2 waits in lock (because thread1 waits in SendMessage). To reset, restart QM.

 

While waiting in lock, the thread does not process messages, even if opt waitmsg 1 used.

 

If mutex is omitted or "", the lock synchronizes only threads in current process (running program, ie QM or exe). With mutex it can synchronize threads in multiple processes. It can be useful, for example, if 'Run in separate process' is checked (see exe). lock creates or opens the mutex. The mutex name must be an unique string, like "QM_mutex_macroname_8469". Error if a kernel object of other type with the same name exists in the system. A mutex with "Global\" prefix can be used by processes in multiple user sessions. With mutex lock is about 8 times slower. You can read more about mutexes and other kernel synchronization objects in MSDN library.

 

Examples

lock
str s="test"
s.setfile("$desktop$\test.txt")
lock-

lock 0 "QM_mutex_test1"
 ...
lock-

lock 0 "" 1000; err end "the code is locked more than 1 s"
 ...
lock-

lock shared_lock_object
 ...
lock- shared_lock_object