65.9K
CodeProject is changing. Read more.
Home

MFC UI Threads

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.28/5 (21 votes)

Aug 18, 2004

2 min read

viewsIcon

90526

downloadIcon

6749

A simple UI thread example.

Image of demo application

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:

  1. If two dialogs are running within 1 thread, then waiting for the lock would halt both threads.
  2. 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()
{
    ...
    // Create a thread to generate a maintain a instance of CThreadexDlg.
    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.

// Get lock. If timeout expires than return fail.
bool CDMLock::Lock(DWORD timeout)
{
    if (mutex) {
        if (WaitForSingleObject(mutex, timeout) == WAIT_OBJECT_0) 
            return true;
    }
    return false;
}

Release Lock (up)

// Release lock.
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;
};