Multithreading in MFC (Microsoft Foundation Class) can be accomplished using either worker threads or UI threads. Here’s an overview of both approaches and how to implement them in MFC.
1. Worker Threads
Worker threads are background threads that don’t interact directly with the user interface (UI). They are useful for performing long-running operations in the background without freezing the main UI.
Example: Creating a Worker Thread
You can create a worker thread using the AfxBeginThread
function.
UINT MyThreadFunction(LPVOID pParam)
{
// Perform your task in the background
for (int i = 0; i < 10; ++i)
{
// Simulate some work
Sleep(1000); // Sleep for 1 second
}
return 0; // Thread completed
}
void StartWorkerThread()
{
CWinThread* pThread = AfxBeginThread(MyThreadFunction, NULL);
if (pThread == nullptr)
{
AfxMessageBox(_T("Thread creation failed!"));
}
}
MyThreadFunction
: The function that will run on the worker thread.AfxBeginThread
: Used to create a new worker thread.
Communication Between UI and Worker Thread
If you want the worker thread to communicate with the UI (e.g., to update progress), you should use thread-safe mechanisms like posting messages to the main thread.
UINT MyThreadFunction(LPVOID pParam)
{
CWnd* pWnd = (CWnd*)pParam;
for (int i = 0; i < 10; ++i)
{
// Simulate work
Sleep(1000);
// Post a message to the main thread to update progress
pWnd->PostMessage(WM_USER_UPDATE_PROGRESS, i);
}
return 0;
}
// In your dialog class
afx_msg LRESULT OnUpdateProgress(WPARAM wParam, LPARAM lParam)
{
int progress = (int)wParam;
// Update UI with progress
return 0;
}
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
ON_MESSAGE(WM_USER_UPDATE_PROGRESS, &CMyDialog::OnUpdateProgress)
END_MESSAGE_MAP()
PostMessage
: Sends a message from the worker thread to the UI thread.ON_MESSAGE
: Declares a handler for custom messages in MFC.
2. UI Threads
UI threads in MFC are threads that have their own message loops. These threads are used when you need to create or manipulate UI elements (such as windows or dialogs) in the new thread.
Example: Creating a UI Thread
class CMyUIThread : public CWinThread
{
DECLARE_DYNCREATE(CMyUIThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
};
IMPLEMENT_DYNCREATE(CMyUIThread, CWinThread)
BOOL CMyUIThread::InitInstance()
{
// Create a dialog or window here
CDialog myDialog(IDD_MY_DIALOG);
myDialog.DoModal(); // Modal dialog
return TRUE;
}
int CMyUIThread::ExitInstance()
{
// Cleanup code here
return CWinThread::ExitInstance();
}
void StartUIThread()
{
CWinThread* pThread = AfxBeginThread(RUNTIME_CLASS(CMyUIThread));
if (pThread == nullptr)
{
AfxMessageBox(_T("UI Thread creation failed!"));
}
}
CWinThread
: Base class for both worker and UI threads in MFC.InitInstance
: Where you initialize any UI components in the thread.ExitInstance
: Handles thread cleanup.
Thread Synchronization
When multiple threads access shared resources, you should use synchronization primitives such as CRITICAL_SECTION, CMutex, or CEvent to avoid race conditions.
Example: Using Critical Sections
CRITICAL_SECTION cs;
void SomeSharedFunction()
{
EnterCriticalSection(&cs);
// Access shared resource
LeaveCriticalSection(&cs);
}
void InitializeCriticalSectionExample()
{
InitializeCriticalSection(&cs);
// Make sure to delete the critical section once you're done
DeleteCriticalSection(&cs);
}
This ensures that only one thread can access the critical section at a time, avoiding race conditions.
Summary
- Worker Threads: Perform background work; use
AfxBeginThread
to create them. - UI Threads: Handle UI components in a separate thread; use
CWinThread
andAfxBeginThread
for creation. - Synchronization: Use thread-safe methods like critical sections, mutexes, or events for resource sharing.
Let me know if you need any further details or specific examples!
Leave a Reply