01-05-2026 04:13 PM - edited 01-05-2026 04:19 PM
Our LabWindows/CVI 2017 app has UI buttons that run functions that send a bunch of messages to various devices. The message code is in a DLL. I used CmtGetLock() in that DLL so the background thread (which is polling the devices) cannot be interrupted by a user UI click.
Today I found a bug where blasting messages causes the app to crash (it just disappears, no error dialog). If I do the same from the LabWindows debugger, I get an error box with an unknown location (likely in the DLL, then, since no source code is available for that external code).
I only recently (last week or so) learned that the threadsafe variable macros do not lock when used from the same thread. I suspect the Cmt locking functions may be the same. The help sounds like it could be the case:
"When you finish using the thread lock, you must release the lock by calling CmtReleaseLock from the same thread that called this function. Only one thread can get ownership of the thread lock at a time. If a thread requests the lock while another thread owns the lock, the calling thread waits in this function until the owning thread releases the lock. You can call this function from the same thread more than once, but you must call CmtReleaseLock once for each time that you called this function."
If that is the case, I need to use a solution that will lock even when called from the same thread via a UI click.
Where should I be looking?
01-06-2026 02:57 PM
I have done some testing, and while button click callbacks do not normally interrupt themselves, the moment they call anything with a ProcessSystemEvents() that allows another instance of a click to start running the same callback. This is the main issue I am trying to resolve.
As a workaround, I am putting in extra code on each callback to block it from running if it is already running, but having a simple resource lock would be a nicer approach, I think.
01-16-2026 06:18 AM
Those multithreading locks exist to protect from multithreading parallel access. If your UI (main) threaded function calls ProcessSystemEvents() to allow UI processing that then results in another call of your function you do NOT want to lock execution there, that would very likely create a mutual exclusion lock and your application would eventually stop working at all.
You will almost certainly want to have a variable in your context relevant structure or similar that indicates if processing is already busy and either skip the same processing or post the further processing to a queue of some sort to be picked up later. And you want to use an atomic set_and_check() function or similar (Windows API function would be InterlockedCompareExchange() and its friends) that guarantees that setting the lock and verifying its state is actually done in a single uninterruptable operation. Not sure about the exact library in CVI, it's been a long time that I worked in it, but I believe to remember that it had something like this.
01-16-2026 08:15 AM
@rolfk wrote:
And you want to use an atomic set_and_check() function or similar (Windows API function would be InterlockedCompareExchange() and its friends) that guarantees that setting the lock and verifying its state is actually done in a single uninterruptable operation. Not sure about the exact library in CVI, it's been a long time that I worked in it, but I believe to remember that it had something like this.
That is exactly what I am needing. My original background was the OS-9 RTOS, and it had fast binary semaphores and things called events that could lock with data (with automatic increment and such). I have no Windows background, and all my early searching led me to the Cmt stuff I am trying to use.
When we build this DLL outside of LabWindows, I used a mutex thing in Windows. I just need to find a simple lock to use on this hardware device that can work with LabWindows, but also has something we can use as we move away from using the LabWindows compiler.
01-21-2026 02:44 AM - edited 01-21-2026 02:45 AM
While I don't know exactly how atomic and fast they are, mutexes can be used in CVI as well. This is an example I used to interlock two different applications not to be run simultaneously:
HANDLE mxH = NULL;
//HANDLE WINAPI CreateMutex(
// __in LPSECURITY_ATTRIBUTES lpMutexAttributes,
// __in BOOL bInitialOwner,
// __in LPCTSTR lpName
//);
mxH = CreateMutex (
NULL, //LPSECURITY_ATTRIBUTES lpMutexAttributes,
TRUE, //BOOL bInitialOwner,
"MyMutex" //LPCTSTR lpName
);
if (!mxH)
MessagePopup ("Warning !", "Error in allocating system resource (mutex)");
else if (GetLastError() == ERROR_ALREADY_EXISTS) {
// Mutex already existing, created by another application
MessagePopup ("Warning !", "Other application is running!\nIn this conditions you cannot run this app.");
return 0;
}
In this case the mutex is automatically destroyed when the program terminates so no need to dispose of it explicitly.
Running in a single app you could use CreateMutex (), WaitForSingleObject (), OpenMutex () and ReleaseMutex () to interlock your processes.
01-21-2026 10:11 AM
@RobertoBozzolo wrote:
While I don't know exactly how atomic and fast they are, mutexes can be used in CVI as well. This is an example I used to interlock two different applications not to be run simultaneously:
Ah, that looks like what I used for the non-CVI compiler. I created a wrapper of lock/unlock functions so I could swap them out easily:
bool DLLEXPORT DLLSTDCALL LockInit (void);
bool DLLEXPORT DLLSTDCALL LockObtain (unsigned int lockTimeoutMs);
bool DLLEXPORT DLLSTDCALL LockRelease (void);
bool DLLEXPORT DLLSTDCALL LockTerm (void);
void DLLEXPORT DLLSTDCALL LockTimeout (unsigned int lockTimeoutMs);
Those all started out using the CVI call, then I made it conditionally compile using the stuff from windows.h:
bool DLLEXPORT DLLSTDCALL LockInit (void)
{
bool status = true; // Assume success.
#ifdef _CVI_
char cmtStatusMessage[CMT_MAX_MESSAGE_BUF_SIZE];
int cmtStatus = 0; // 0 == Success
if (0 == g_Lock) // Automatic initialization
{
// Intiialize a new lock that supports timeout.
cmtStatus = CmtNewLock ("", OPT_TL_SUPPORT_TIMEOUT |
OPT_TL_PROCESS_EVENTS_WHILE_WAITING,
&g_Lock);
// This function returns 0 to indicate success and negative values to
// indicate failure. Pass the CmtStatus code to CmtGetErrorMessage
// to get a description of the error code.
if (0 != cmtStatus)
{
status = false; // Init failed.
if (CmtGetErrorMessage (cmtStatus, &cmtStatusMessage[0]) == 0)
{
DebugPrintf ("CmtNewLock failed: %s\n", cmtStatusMessage);
}
}
}
#else // Windows API
// Only create if not already created.
if (NULL == g_MutexHandle)
{
g_MutexHandle = CreateMutex (NULL, FALSE, NULL);
// if (NULL == g_MutexHandle)
// {
// DebugPrintf ("CreateMutex failed: %u\n", GetLastError());
// }
}
status = (g_MutexHandle != NULL); // NULL == error
#endif // _CVI_
return status;
} // end of LockInit ()
bool DLLEXPORT DLLSTDCALL LockObtain (unsigned int lockTimeoutMs)
{
bool status = false; // Assume failure.
// If calling directly, like from within this DLL, we can pass in any
// value we want. To allow code using the DLL to change the value, pass
// in 0 and it will use the static variable that can be set externally
// using the LockTimeout() function.
if (0 == lockTimeoutMs)
{
lockTimeoutMs = S_LockTimeoutMs;
}
#ifdef _CVI_
// To wait forever, LavWindows uses CMT_WAIT_FOREVER which is defined as
// 0xFFFFFFFF.
char cmtStatusMessage[CMT_MAX_MESSAGE_BUF_SIZE];
int cmtStatus = 0; // 0 == Success
int obtainedLock = 0;
if (LockInit () == true) // Init if needed.
{
// Try to get the lock, processing events, with a timeout.
cmtStatus = CmtGetLockEx (g_Lock, 1, lockTimeoutMs, &obtainedLock);
if (0 != cmtStatus)
{
if (CmtGetErrorMessage (cmtStatus, &cmtStatusMessage[0]) == 0)
{
DebugPrintf ("CmtGetLockEx failed: %s\n", cmtStatusMessage);
}
}
else // Call worked, but did we obtain the lock?
{
if (1 != obtainedLock)
{
DebugPrintf ("CmtGetLockEx did not obtain lock within %d ms.\n",
lockTimeoutMs);
}
else
{
status = true; // Locked!
}
}
} // end of if (0 != g_Lock)
#else // Windows API
// Create the lock in case it doesn't already exist.
status = LockInit ();
if (status == true)
{
// Block until we have the lock.
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject (g_MutexHandle, lockTimeoutMs);
switch (dwWaitResult)
{
case WAIT_OBJECT_0: // We have the lock.
status = true;
break;
case WAIT_TIMEOUT: // We did not get the lock.
// DebugPrintf ("WaitForSingleObject did not obtain lock within %d ms.\n",
// lockTimeoutMs);
break;
default:
break;
}
}
#endif // _CVI_
return status;
} // end of Lock()
...and so on. (NOTE: I wanted this to init on its own if the user forgot to do LockInit() first, so I use a global variable. I have since realized that if two threads tried to do this at the same time, it could cause a problem. I'll have to update that code when I figure out how to make this work like we need for locking the I2C USB connection.)
I have no idea of my Windows mutex code is correct. I figured it out doing searches and such. I should let AI look at it and see if it can offer any suggestions.