Quantitative Analysis
Parallel Processing
Numerical Analysis
C++ Multithreading
Python for Excel
Python Utilities
Services
Author

I. Installation.
II. Threading primitives.
1. Encapsulation of primitives.
2. Preventing starvation.
3. Preventing race condition.
A. Guard primitives.
4. Barriers.
III. NonBlockingQueue.
IV. ThreadPool.
V. ThreadMaster.
VI. OTS Scheduler.
VII. Bibliography
Downloads. Index. Contents.

Preventing race condition.


ace condition happens when a thread-shared resource is not properly protected. The protection itself is an expensive operation. Hence, the programmer tends to optimize and makes errors. Such errors are hard to detect because of the nature of the race condition. We follow ideas of the article [Alexandrescu1] and provide tools for compiler-assisted prevention of such errors. We define Guard objects and follow the following design rules:

Definition

(Multi-threaded design rules)

1. Thread-safe member functions are declared volatile.

2. Thread-unsafe member functions are not volatile.

3. Locked shared objects are passed into functions as Guard objects.

4. Unlocked shared objects are passed into functions with volatile type modifier.




Consider the following code:

#include <ots/threading/RWMutex.hpp>

#include <ots/threading/WriterGuard.hpp>

#include <ots/threading/ReaderGuard.hpp>

#include <ots/otsConfig.hpp>

class X

{

public:

typedef ots::config::RWMutex::type Mutex;

private:

mutable Mutex theMutex;

std::string theString;

public:

Mutex& mutex() const { return theMutex; }

void set( const char* x ) { theString=x; }

std::string get() const { return theString; }

};

void func1(volatile X& x)

{

typedef ots::config::WriterGuard<X,X::Mutex>::type Guard;

Guard(x)->set("Hello.");

}

void func2(volatile X& x)

{

typedef ots::config::ReaderGuard<X,X::Mutex>::type Guard;

std::string s=Guard(x)->get();

}

The class X is meant for multi-threaded access. The interaction with the Guard primitives requires that the class X would expose its mutex via the member function mutex().

The func2 reads contents of some class X. It must use the ReaderGuard that removes volatileness and exposes only the const-part of the interface of the class X. An attempt to access the x directly results in a compiler error.

The func1 writes into the class X and uses the WriterGuard to access the entire interface.

For all access to the threading primitives we use the metafunctions defined in the otsConfig.hpp. The file otsConfig.hpp is declarative: we still need to include the concrete implementation headers RWMutex.hpp, WriterGuard.hpp and ReaderGuard.hpp.

Such organization does not prevent from unlocked modification of primitive data types using built-in operations. The following code compiles.

class X

{

private:

double theX;

public:

void f() volatile

{

theX++;

}

};

This problem may be solved with a pointer indirection but this would also create to much of performance hit. We also could have preprocessor-based DEBUG and RELEASE versions but the difference between the versions would defeat the purpose. In the present project this problem is left unsolved.




A. Guard primitives.

Downloads. Index. Contents.


















Copyright 2007