Click here to Skip to main content
15,868,030 members
Articles / Programming Languages / C++
Article

Synchronized multi-threading in C++ (No MFC!)

Rate me:
Please Sign up or sign in to vote.
3.59/5 (41 votes)
19 Apr 2007BSD4 min read 290.6K   9K   94   69
A C++ wrapper for Win32 multi-threading

Introduction

Have you ever found multi-threading and thread synchronization difficult tasks in Win32? Then try these classes. Here I provide a small code library that will give you tools for creating multi-threaded applications in the C++ way, with out using MFC. If you have done multi-threading in Java and got fed up with the thread classes in MFC, you have come to the right place. Enough talking, I will take you right away through a step-by-step tutorial on using these classes.

Background

You should be familiar with OOPs. You should also be familiar with terms like virtual functions, overriding, namespaces, exceptions etc. But you need not be a C++ guru.

Using the code

First, I will give you the list of header files you should include in the CPP file that use my thread classes:

#include <STRING>
using namespace std;

#include "ou_thread.h"
using namespace openutils;

The next step is to create a customized Thread class from the base Thread class that you find in ou_thread.h:

class MyThread : public Thread {
private:
    int m_nCount;
public:
    MyThread(int n,const char* nm) {
        Thread::setName(nm);
        m_nCount = n;
    }
    void run() {
        for(int i=0;i<m_nCount;i++) {
            cout << getName().c_str() << ":" << i << endl;
        }
    }
};

If you have done thread programming in Java, the above class will look familiar. First we have inherited publicly from the Thread class and then we gave our own implementation to the run() function. The MyThread class we just created has a private integer variable which is used by the run() function to print out the thread's name that much time. The setName() and getName() functions are derived from the base class.

Now let us create a main() function to test the MyThread class:

int main() {
    Thread *t1 = new MyThread(15,"Thread 01");
    Thread *t2 = new MyThread(10,"Thread 02");
    try {
        t1->start();
        t2->start();
        t1->stop();
        t2->stop();
    }catch(ThreadException ex) {
      printf("%s\n",ex.getMessage().c_str());
  } 
  delete t1;
  delete t2;
  return 0;

Here we created two thread pointers pointing to MyThread objects.

The MyThread constructor takes two arguments, value of the counter variable and the thread name. Then we start both these threads by calling the start() function, which in turn calls our implementation of run(). If the low-level thread creation was not successful, then the try-catch block will handle that problem gracefully.

When you run this program, you will get output much like the following:

ThreThread 02:0
Thread 02:1
Thread 02ad 01:1
Thread 01:2
Thread 01:3
Thr:2
Thread 02:3
Thread 02:4
Thread 0ead 01:4
Thread 01:5
Thread 01:6
Th2:5
Thread 02:6
Thread 02:7
Thread read 01:7
Thread 01:8
Thread 01:9
T02:8

Thread synchronization

You can see that thread2 is executing the run() function before thread1 has finished and both threads execute together to produce a confusing result. This can be more serious if both threads are accessing a critical resource like a database file at the same time. This problem can be solved by using a Mutex object.

A Mutex is a synchronization object that allows one thread mutually exclusive access to a resource. We can create a mutex using the Mutex class and hand over its ownership to the first thread. The next thread can be made to "wait" until the first thread "releases" the ownership of that object. Let us see how this can be achieved.

First include the following declaration to the main() function just before calling t1->start();

Mutex m("MyMutex");

This will create a mutex object identified by the name MyMutex. We can use this object in the run() function to control access to shared code. Modify the run() function in MyThread class to include calls to wait() and release() functions:

void run() {
        wait("MyMutex");
        for(int i=0;i<m_nCount;i++) {
            cout << getName().c_str() << ":" << i << endl;
        }
        release("MyMutex");
    }

Please keep in mind that mutex names are case sensitive. If the mutex is not found, then wait() and release() functions will throw a ThreadException. Now recompile and run the program. You will see the following output:

Thread 01:1
Thread 01:2
Thread 01:3
Thread 01:4
Thread 01:5
Thread 01:6
Thread 01:7
Thread 01:8
Thread 01:9
Thread 01:10
Thread 01:11
Thread 01:12
Thread 01:13
Thread 01:14
Thread 02:0
Thread 02:1
Thread 02:2
Thread 02:3
Thread 02:4
Thread 02:5
Thread 02:6
Thread 02:7
Thread 02:8
Thread 02:9

You can see how thread2 waits until thread1 is finished, to produce the desired output. Using mutexes has their own overhead and tends to slow down everything. So use them when only one thread at a time should be allowed to modify data or some other controlled resource.

If synchronized by a mutex, it is important to call stop() on all threads in the same order start() was called on them. If no mutex was used, you can avoid calling stop() on threads.

Call the release() function of mutex after the calls to stop() functions of the thread objects.

t1->stop();
t2->stop();
m.release();

Thread priority

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level does scheduling of threads at a lower level take place.

The setPriority() function enables setting the base priority level of a thread relative to the priority class of its process. This function can take any of the following values as its only argument:

Priority ValueMeaning
Thread::P_ABOVE_NORMALIndicates 1 point above normal priority for the priority class.
Thread::P_BELOW_NORMALIndicates 1 point below normal priority for the priority class.
Thread::P_HIGHESTIndicates 2 points above normal priority for the priority class.
Thread::P_IDLEKeeps this thread idle.
Thread::P_LOWESTIndicates 2 points below normal priority for the priority class.
Thread::P_NORMALIndicates normal priority for the priority class.
Thread::P_CRITICALPuts the thread in the highest possible priority.

For example, the following code puts thread1 in a high priority:

t1->setPriority(Thread::P_HIGHEST);

By default, a thread is created with the P_NORMAL priority.

Running the demo project

To run the demo project, create a Win32 console application in your Visual C++ IDE, add the demo project files to it and compile.

History

  • Created: October 14th, 2003
  • Updated source: 9 July 2004

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: Linking error Pin
AnOldGreenHorn20-Feb-06 17:53
AnOldGreenHorn20-Feb-06 17:53 
GeneralRe: Linking error Pin
mcd9021-Feb-06 2:17
mcd9021-Feb-06 2:17 
GeneralRe: Linking error Pin
AnOldGreenHorn21-Feb-06 17:21
AnOldGreenHorn21-Feb-06 17:21 
GeneralAn error when i add a sleep() in run() Pin
Surpaimb21-Sep-05 23:57
Surpaimb21-Sep-05 23:57 
GeneralRe: An error when i add a sleep() in run() Pin
AnOldGreenHorn22-Sep-05 17:40
AnOldGreenHorn22-Sep-05 17:40 
GeneralRe: An error when i add a sleep() in run() Pin
Surpaimb23-Sep-05 18:38
Surpaimb23-Sep-05 18:38 
GeneralAVOID to wait time-consuming tasks Pin
frank.fang25-Apr-07 0:04
frank.fang25-Apr-07 0:04 
GeneralSequential in ATL Win Service Pin
Anonymous6-Aug-05 4:14
Anonymous6-Aug-05 4:14 
I am using 5 of these threads...inside a loop executing SPs and working with each one recordset...the deal is...when the first recover its recordset and begin to work the rest wait till that finish, everything inside an ATL WService(...COINIT_MULTITHREADED)...here a piece of code explaining:

function X()
{
while(flag)
{
if (ThreadLogin->m_hThread == NULL)
ThreadLogin->start();
if(ThreadLocales->m_hThread == NULL)
ThreadLocales->start();
if (ThreadRemotos->m_hThread == NULL)
ThreadRemotos->start();
if (ThreadColayRemotos->m_hThread == NULL)
ThreadColayRemotos->start();
if( ThreadRemotosMirror->m_hThread == NULL)
ThreadRemotosMirror->start();


if (ThreadLogin->m_hThread != NULL)
ThreadLogin->stop();//when the function get in here
//the program (NT service) waits the thread finish...
if (ThreadLocales->m_hThread != NULL)
ThreadLocales->stop();
if (ThreadRemotos->m_hThread != NULL)
ThreadRemotos->stop();
if (ThreadRemotos->m_hThread != NULL)
ThreadRemotos->stop();
if (ThreadColayRemotos->m_hThread != NULL)
ThreadColayRemotos->stop();
}
}

Excuse me if its evident but i am clogged

GeneralError adding to my project Pin
buho_usp2-Jun-05 9:15
buho_usp2-Jun-05 9:15 
GeneralRe: Error adding to my project Pin
AnOldGreenHorn2-Jun-05 17:49
AnOldGreenHorn2-Jun-05 17:49 
GeneralRe: Error adding to my project Pin
Anonymous4-Aug-05 12:47
Anonymous4-Aug-05 12:47 
Generalawesome! Pin
Sebastian Pipping24-Mar-05 10:33
Sebastian Pipping24-Mar-05 10:33 
Generalthread Pin
Anonymous7-Mar-05 20:18
Anonymous7-Mar-05 20:18 
GeneralSocket prog or threading Pin
Dablu4-Feb-05 1:19
Dablu4-Feb-05 1:19 
GeneralRe: Bug - ExitThread() Pin
AnOldGreenHorn25-Oct-04 1:32
AnOldGreenHorn25-Oct-04 1:32 
GeneralRe: Bug - ExitThread() Pin
AnOldGreenHorn2-Jun-05 17:54
AnOldGreenHorn2-Jun-05 17:54 
GeneralUse WaitForSingleObject with caution! Pin
Volker von Einem20-Jul-04 20:11
Volker von Einem20-Jul-04 20:11 
GeneralRe: Use WaitForSingleObject with caution! Pin
AnOldGreenHorn21-Jul-04 2:18
AnOldGreenHorn21-Jul-04 2:18 
GeneralRe: Use WaitForSingleObject with caution! Pin
bandanna2k14-Feb-07 6:46
bandanna2k14-Feb-07 6:46 
GeneralSo Good Pin
Hing14-Jul-04 16:03
Hing14-Jul-04 16:03 
GeneralSlice of CPU time Pin
Pablez18-Feb-04 21:16
Pablez18-Feb-04 21:16 
GeneralRe: Slice of CPU time Pin
John M. Drescher13-Jul-04 8:50
John M. Drescher13-Jul-04 8:50 
GeneralThe dinning philosopher's problem using threads Pin
ignacio nacho18-Feb-04 13:43
ignacio nacho18-Feb-04 13:43 
GeneralRe: The dinning philosopher's problem using threads Pin
Roberto Guerzoni13-Jul-04 2:42
professionalRoberto Guerzoni13-Jul-04 2:42 
GeneralThread Exit Pin
glove15-Oct-03 19:57
glove15-Oct-03 19:57 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.