Introduction
This article describes a quick UI thread implementation. Running the demo project will create two modal dialog windows. They will initially appear right on top of each other. Move the top window off to the side so you can see both windows.
Each dialog is run in a different thread, and each dialog will maintain a separate message loop. This behavior can be seen by clicking on the Lock button for each thread. After clicking on "Lock", the thread will attempt to acquire access to the named lock "ThreadLockExample
". If the thread gets access to the lock, a "Got Lock" message will be displayed. If the thread is unable to get access to the lock, then a "Waiting" message will be displayed. The locking behavior seen in these two dialogs could not occur without using UI threads. Why? There are 2 reasons:
- If two dialogs are running within 1 thread, then waiting for the lock would halt both threads.
- You could not create a separate dialog in a worker thread. Worker threads do not have a message loop.
Source Code
- Lock.h/cpp
Manages a single lock, and abstracts away implementation details from user.
- UIThread.h/cpp
Implementation of a UI thread.
- ThreadExDlg.h/cpp
Thread dialog.
- ThreadEx.h/cpp
Thread example main app.
Code Notes
Creating a thread
To create a user interface thread, create an instance of a class derived from CWinThread
. Then, call the method CreateThread
. See UIThread.h/cpp and ThreadEx.cpp for more information.
class UIThread : public CWinThread
...
};
...
BOOL CThreadexApp::InitInstance()
{
...
thread.CreateThread();
...
}
Create a mutex (lock)
To create a lock, just call CreateMutex(...)
. See Lock.h/cpp.
CDMLock::CDMLock(const CString & name)
{
mutex = CreateMutex(NULL, 0, name);
}
Acquire lock (down)
Call WaitForSingleObject(...)
. You can optionally pass a timeout value. When you have waited longer than the specified time, the function WaitForSingleObject
will return WAIT_TIMEOUT
. If the lock is acquired successfully, it will return WAIT_OBJECT_0
.
bool CDMLock::Lock(DWORD timeout)
{
if (mutex) {
if (WaitForSingleObject(mutex, timeout) == WAIT_OBJECT_0)
return true;
}
return false;
}
Release Lock (up)
bool CDMLock::Unlock()
{
if (mutex) {
if (ReleaseMutex(mutex))
return true;
}
return false;
}
CDMLock (Reusable)
Most of the code included in the download for this article is demo code. But the class CDMLock
(lock.h/cpp) is kind of a nice class to have around. While working with locks really is not that difficult, it is always nice to have the details abstracted away. CDMLock
is pretty simple to use. Just pass a string into the constructor to create a Named Lock. Then call Lock
to acquire access to the lock. Call Unlock
to release the lock. For an example of the usage of CDMLock
, look at ThreadExDlg.cpp.
The CDMLock
class can also be used for two processes running on the same computer, not just two threads in the same process.
class CDMLock
{
public:
CDMLock(const CString & name);
virtual ~CDMLock();
bool Unlock();
bool Lock(DWORD timeout = INFINITE);
private:
HANDLE mutex;
};