Click here to Skip to main content
Click here to Skip to main content

Simple Multithreaded Application in pure C, Win32 and MFC

By , 30 Nov 2003
 

Introduction

A thread is a path of execution. A process requires at least one thread. But, it may contain more then one thread. If the process is closed, all the threads in that process are killed automatically. When we create a thread in an application that is actually a secondary thread. In C or C++ the program entry point is main or wmain (Unicode version). In windows application the program starts in WinMain or wWinMain. When the program starts, the operating system creates the first thread. Because, Windows is a multitasking operating system.

Thread function

Thread function is like an ordinary function with long void pointer parameter. We can pass any data through void pointer data type.

A simple thread function looks like

ThreadFunction(LPVOID param)
{
    // do somthig

    ......
    .......

    //return value;

}

Thread Priorities

The thread priority controls the thread process priority. The thread priorities are following.

  • Highest THREAD_PRIORITY_HIGHEST
  • Above Normal THREAD_PRIORITY_ABOVE_NORMAL
  • Normal THREAD_PRIORITY_NORMAL
  • Below Normal THREAD_PRIORITY_BELOW_NORMAL
  • Idle THREAD_PRIORITY_IDLE

We set thread priority with the CreateThread function. We get or set thread priorities in GetThreadPriority and SetThreadPriority Win32API functions or CWinThread’s functions which we call freely in the code. The priority functions return a BOOL value.

C Run Time Library Multithreading

_beginthread
_beginthreadex
_endthread
_endthreadex

All the above c run time library functions are in the process.h header file. Make sure the Microsoft Visual Studio project setting is as multithreaded DLL. The _beginthread and _beginthreadex functions are used to create threads in C run time library. But, these functions have some differences. The _beginthreadex has some add ional parameters like security and thread address. When we create thread using _beginthread we end the thread use _endthread. The _endthread closes thread handle automatically. But, if we use _endthreadex we close the nthread handle using CloseHandle Win32 API function. The C Run Time Library contains the Thread Local Storage (TLS) internally. We can use thread local storage using API or Compiler specific code. The TlsAlloc, TlsFree, TlsGetValue and TlsSetValue are used to store thread specific data. Microsoft recommend that If you use _beginthread functions for C run Time Library you can not use Win32 API like ExitThread or CreateThread. Because, if use that method it might result in deadlocks. _beginthread uses multiple arguments in the thread creation. Our example program is a simple console based application. The user enters number of threads to create and then we execute each thread.

// Secound Thread function
void ThreadProc(void *param);

// First thread
int main()
{

    int n;
    int i;
    int val = 0;
    HANDLE handle;

    printf("\t Thread Demo\n");

    printf("Enter the number of threads : ");
    scanf("%d",&n);


    for(i=1;i<=n;i++)
    {
        val = i;
        handle = (HANDLE) _beginthread( ThreadProc,0,&val); // create thread
        WaitForSingleObject(handle,INFINITE);


    }


    return 0;
}


void ThreadProc(void *param)
{

    int h=*((int*)param);
    printf("%d Thread is Running!\n",h);
    _endthread();

}

The thread waits for completion of another thread using WaitForSingleObject Win32 API function.

MFC Multithreaded

The CWinThread is the base class for all thread operations. MFC supports two types of threads. These are User Interface Thread and Worker thread. The user interface thread is based on windows message. The worker thread runs in the background process. (Examples, search a file in the find window or communicate with web browser in the web server) . The CWinThread supports both worker thread and User interface Threads. But, we will discuss only worker threads.

The MFC class hierarchy

CObject
    CCmdTarget
        CWinThread
            CWinApp

In the above class hierarchy the CWinApp application class is derived from CWinThread. So, if we create a application the thread is also created. If we create a thread, that is a secondary thread. The mother class CObject has some features like, Serialization support, Run time Class information and Debugging support. The derived class CWinThread also has the same features. The most common useful data members and member functions are the following.

Data members

  • m_hThread The current thread handle
  • m_bAutoDelete Whether the thread has set to auto delete or not
  • m_nThreadID The current thread ID

Data Functions:

  • CreateThread Start the exec execution of thread
  • SuspendThread Increment thread suspend count. When the resume thread occur only the thread resume.
  • ResumeThread Resume the thread. Decrements the thread count stack
  • SetThreadPriority Set thread priority ( LOW, BELOW LOW or HIGH)
  • GetThreadPriority Get the thread Priority

Not all the member functions in MFC as class members. We can access some functions globally also. These functions begin with Afx. The AfxBeginThread, AfxEndThread are most widely useful functions in MFC thread. We create thread using AfxBeginThread function. AfxBeginThread Syntax:

CWinThread* AfxBeginThread( AFX_THREADPROC ThreadProc, LPVOID Param,
      int nPriority = THREAD_PRIORITY_NORMAL,UINT nStackSize = 0,
      DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );

The ThreadProc is first Parameter in AfxBeginThread function. We use name of thread function in this parameter. We pass the void pointer arguments in this function. The return type in the function is UINT. The other arguments in AfxBeginThread are optional. The default thread priority is THREAD_PRIORITY_NORMAL. We can change this any time using CwinThread SetThreadPriority function. We also get the thread priority.

The Thread terminates using AfxEndThread. The AfxEndThread has a Exit code argument list.

CwinThread *pThread = AfxBeginThread( ThreadFunction, &data);


UINT ThreadFunction(LPVOID param)
{
    DWORD result =0 ;

    // do somthig

    AfxEndThread(exitCode);
    return result;

}

Win32 Multithread

Win32 Thread created by CreateThread function. The syntax in CreateThread is following

HANDLE CreateThread(  LPSECURITY_ATTRIBUTES lpThreadAttributes,
            DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,  DWORD dwCreationFlags, LPDWORD lpThreadId);

We terminate thread using the following methods.

  1. use TerminateThread function
  2. use ExitThread function
  3. use return

But, Advanced Windows by Jeffery Ritcher recommends us to use the return method. TerminateThread or ExitThread function does not clear the Thread Stack properly. The GetThreadTimes is used to find the thread’s run time. The GetCurrentThreadID is to get current thread ID. The Sleep function is to sleep a particular thread for so many milliseconds. Example Sleep (1000) will sleep the thread for 1000 milliseconds. The SwithToThread is to switch to other threads. The SuspendThread is to wait until a call of resume Thread. The WaitForSingleObject is to wait when a particular thread completes its work. The WaitForMultipleObject is used for multiple events. These functions wait for following situations - Change notification, Console input, Event, Job, Mutex ,Process, Semaphore, Thread and Waitable timer.

Benefits of Threads

The multithreaded application uses CPU 100% effectively. When we create a process, it will take more memory space. The multithreaded application shares the same process memory space. Every thread contains stack. So, the thread takes up less memory usage compared to a Process. The process may or may not contain more threads. If you run two or more threads in a process, all the threads share the process address space.

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

R.selvam
Software Developer (Senior)
India India
Member
Selvam has worked on several technologies like Core Java, VC++, MFC, Windows API and Weblogic server. He takes a lot of interest in reading technical articles and enjoy writing them too. He has been awarded as a Microsoft Community Star in 2004, MVP in 2005-06, SCJP 5.0 in 2009, Microsoft Community Contributor(MCC) 2011.
 
Web site: http://www15.brinkster.com/selvamselvam/

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 3membervenkat.yva9 May '13 - 0:28 
nice
GeneralMy vote of 2memberranjithkumar8120 Dec '12 - 19:53 
Hi Selvam,
I have some query, related to multithreading.
 
I am able to create a multithred using afxbeginthread ,But each thread suppose to perform different task.
 
Example :
1)insert the data into database and another one read the data from database.
 
Please give some examples .
GeneralMy vote of 5memberzssureqh30 Aug '12 - 18:51 
It is useful for me to learn about the working threads and UI threads.Thanks
Questionthreding for multi core programmingmembersuhas paruchuri23 Apr '12 - 0:31 
do u know any website to learn threading for muti core programming in c if u know any thing pease mail to(suhas.pandu123@gmai.com)
GeneralMy vote of 5memberKirowOnet5 Dec '11 - 7:34 
It works without dancing with a tambourine.Thx
Generalerror "call to undefined function _beginthread" borland c++ 5.02memberfspluto25 Jan '10 - 20:33 
hi folks
i am using borland c++ compiler version 5.02. got to write a multiy threaded application with two threads running simultaneously.
my code includes process.h but on compilation i get error
"call to undefined function _beginthread" and "call to undefined function _endthread" . Frown | :(
 
searched a lot on net but of no use.
seems there is something wrong with the process.h files included .
the following is the code :
 
( its a surprise that this code is a simple "copy paste " from borland's example codes for multithreading Laugh | :laugh: )
 
any help / comments would be greatly appreciated Smile | :)
 
*********************************************************************
*********************************************************************
#include <stdio.h>
#include <errno.h>
#include <stddef.h> /* _threadid variable */
#include <process.h> /* _beginthread, _endthread */
#include <time.h> /* time, _ctime */
#include <windows.h>
 
void thread_code(void *threadno)
{
time_t t;
 
time(&t);
printf("Executing thread number %d, ID = %d, time = %s\n",
(int)threadno, _threadid, ctime(&t));
_endthread();
}

void start_thread(int i)
{
int thread_id;
 
#if defined(__WIN32__)
 
if ((thread_id = _beginthread(thread_code,4096,(void *)i)) == (unsigned long)-1)
#else
if ((thread_id = _beginthread(thread_code,4096,(void *)i)) == -1)
#endif
{
printf("Unable to create thread %d, errno = %d\n",i,errno);
return;
}
printf("Created thread %d, ID = %ld\n",i,thread_id);
}
 
int main(void)
{
int i;
 
for (i = 1; i < 20; i++)
start_thread(i);
printf("Hit ENTER to exit main thread.\n");
getchar();
 
return 0;
}
 
*************************************************************************
*************************************************************************
GeneralRe: error "call to undefined function _beginthread" borland c++ 5.02memberR.selvam3 Feb '10 - 0:57 
The _beginthread function available in Multithreaded versions of the Microsoft C run-time libraries. you can check with borland document.
 
You have to compile with: /MT /D "_X86_" /c
 
Thanks and Regards,
Selvam,
http://www.wincpp.com

GeneralHelp: Creating a threadmemberGC1049 Sep '09 - 0:52 
I am creating a vs2005 vc++ application and trying to get a secondary thread setup and working. I have read through the various postings and tried to put some code together but it won't compile.
 
I am trying to start the new thread from a menu item via a message handler based in my application's 'CView' based class. I have created a new class of my own (GcWorkerThread) and is derived from CWinThread, and contains a member function 'GcThreadFunction'
 
calling code:
 

int x;
CWinThread *pThread = AfxBeginThread (GcThreadFunction, x);

 

UINT GcWorkerThread::GcThreadFunction (LPVOID pParam)
{
int t;
for (int y=0; y<1000000; y++
{
}
 
}

 
When is comes to compiling the code I get an error:
"Error C3867 'GcWorkerThread::GcThreadFunction' function call missing argument list
use &GcWorkerThread::GcThreadFunction to create a pointer to member"
 
What am I doing wrong?
:(
GeneralRe: Help: Creating a threadmemberR.selvam9 Sep '09 - 1:57 
try this.
 
int x;
CWinThread *pThread = AfxBeginThread (GcThreadFunction, &x);

 
Thanks and Regards,
Selvam,
http://www.wincpp.com

QuestionPriority in Threadingmemberk.c.sathish18 Aug '08 - 1:42 
I am working in Microsoft VC++. Now i am learning threading concepts.
I executed following code segment in MFC Project. There is no error in program. It's executing but the output wrongly get stored in test.txt file and test1.txt file. I want to know real difference between THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_HIGHEST. See my code segment i given the THREAD_PRIORITY_HIGHEST for WorkerThreadProc which in turn will write the output in test.txt. I used THREAD_PRIORITY_NORMAL for WorkerThreadProc1 to write the output in the file test1.txt. But it's not correctly working. I expected the output to print 100 values in the file test.txt but it is randomly writing the value in the files test.txt and test1.txt. May u clearly give the definition of thread priority and how to use in my program to achieve the output what i expected....
 
UINT WorkerThreadProc( LPVOID Param ) //Sample function for using in AfxBeginThread
{
CFile file;
file.Open("C:\\test.txt",CFile::modeCreate|CFile::modeWrite);
CString strValue;
for(;i<=1000;i++)
{
strValue.Format("Value:%d\n",i);
 
file.Write(strValue,strValue.GetLength()); // Write to the file for worker thread using AfxBeginThread
}
file.Close();
 
return TRUE;
}
UINT WorkerThreadProc1( LPVOID Param ) //Sample function for using in AfxBeginThread
{
CFile file;
file.Open("C:\\test1.txt",CFile::modeCreate|CFile::modeWrite);
CString strValue;
//AfxMessageBox("Hai");
for( i=0;i<=1000;i++)
{
strValue.Format("Value:%d\n",i);
file.Write(strValue,strValue.GetLength()); // Write to the file for worker thread using AfxBeginThread
}
file.Close();
 
return TRUE;
}
 
void CThread_AfxBeginDlg::OnOK()
{
// TODO: Add extra validation here

//CDialog::OnOK();
AfxBeginThread(WorkerThreadProc,NULL,THREAD_PRIORITY_HIGHEST,0,0,NULL);
AfxBeginThread(WorkerThreadProc1,NULL,THREAD_PRIORITY_NORMAL,0,0,NULL);
MessageBox("See the output in C:\\test.txt and test1.txt");
}

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 1 Dec 2003
Article Copyright 2003 by R.selvam
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid