Windows Systems Programming: Spring 2002

[ Home | Syllabus | Course Notes | Assignments | Search]


Threads and MFC (chapter 17)

Two kinds of threads in MFC (both built on win32 thread see saw last class)

Threads can be suspended, resumed or put to sleep.

Thread termination: 

Issue with Autodeletion of CWinThread (p. 992). If you want to access this objects state (why - for return code for one) you must prevent autodeletion - there are two ways to do this. Create thread suspended so you guarantee the ability to set thread state correctly (pp 993-994) - in the off chance it might run and complete and autodelete

Also Create- suspended if you want to wait for thread to end - (like we did in the previous class) because we need handle to non-deleted object

Thread priority discussed pp 999-1000.


C Run-Time Libraries

Contains common "C" function calls (and even if you don't call them MFC might).

There are 6 versions (mostly visual studio does this right - only issue is if you are integrating "C" code)

Debug versions have extensive error checking using "Assert"

NOTE: it is troublesome to call MFC member functions across thread boundaries becuase sometimes some of the object state is in the thread that created the object. A HANDLE IS NOT A POINTER

Design Rule: do all UI manipulation in the main thread.


Sieve of Eratothenes for counting Prime Numbers

// SieveDlg.h

#define WM_USER_THREAD_FINISHED WM_USER+0x100

UINT ThreadFunc (LPVOID pParam);
int Sieve (int nMax);

typedef struct tagTHREADPARMS {
    int nMax;
    HWND hWnd;
} THREADPARMS;
//SieveDlg.cpp
void CSieveDlg::OnStart() 
{
	int nMax = GetDlgItemInt (IDC_MAX);
	if (nMax < 10) {
		MessageBox (_T ("The number you enter must be 10 or higher"));
		GetDlgItem (IDC_MAX)->SetFocus ();
		return;
	}

    SetDlgItemText (IDC_RESULT, _T (""));
    GetDlgItem (IDC_START)->EnableWindow (FALSE);

	THREADPARMS* ptp = new THREADPARMS;
	ptp->nMax = nMax;
	ptp->hWnd = m_hWnd;
	AfxBeginThread (ThreadFunc, ptp);
}

LONG CSieveDlg::OnThreadFinished (WPARAM wParam, LPARAM lParam)
{
    SetDlgItemInt (IDC_RESULT, (int) wParam);
    GetDlgItem (IDC_START)->EnableWindow (TRUE);
    return 0;
}

/////////////////////////////////////////////////////////////////////////////
// Global functions

UINT ThreadFunc (LPVOID pParam)
{
	THREADPARMS* ptp = (THREADPARMS*) pParam;
	int nMax = ptp->nMax;
	HWND hWnd = ptp->hWnd;
	delete ptp;

    int nCount = Sieve (nMax);
    ::PostMessage (hWnd, WM_USER_THREAD_FINISHED, (WPARAM) nCount, 0);
    return 0;
}

int Sieve(int nMax)
{
    PBYTE pBuffer = new BYTE[nMax + 1]; // could be single bit
    ::FillMemory (pBuffer, nMax + 1, 1);

    int nLimit = 2;
    while (nLimit * nLimit < nMax) // what does this loop do?
        nLimit++;

    for (int i=2; i<=nLimit; i++) {
        if (pBuffer[i]) {
            for (int k=i + i; k<=nMax; k+=i)// what does this loop do?
                pBuffer[k] = 0;
        }
    }

    int nCount = 0;
    for (i=2; i<=nMax; i++)
        if (pBuffer[i])
            nCount++;

    delete[] pBuffer;
    return nCount;
}


Writing Thread Safe Programs

MFC Classes are thread safe at the class level NOT the object level

You can wrap a class functions using critical sections to make objects thread safe but there will be a performance penalty.

Remember that if another thread has a pointer to your object - then you may need synchornization.

 




Copyright chris wild 1999-2002.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 24, 2002.