Introduction
This article demonstrates the use of mutexes and templates to achieve transparency in source code when dealing with mutexed variables. It's also small hack to minimize code rewriting when you want multi-threaded solutions ported from single-threaded ones.
Next, i'll give you some background about the concepts behind this article and how to use the developed code in your applications.
Background
Let's start with a simple example of a single-threaded application performing some operations:
boolean CanStartStep2 = false;
void compute()
{
for (int i = 0; i < 500; i++)
{
if (i == 50)
CanStartStep2 = true;
}
while (!CanStartStep2)
;
for (int i = 0; i < 100; i++)
{
}
}
It's easy to understand that the given example could be split into worker threads, something like the next example (keep in mind that this is a simple example):
boolean CanStartStep2 = false;
CMutex mut;
static UINT Thread1Proc(LPVOID)
{
mut.Lock();
CanStartStep2 = false;
mut.Unlock();
for (int i = 0; i < 50000; i++)
{
if (i == 10)
{
mut.Lock();
CanStartStep2 = true;
mut.Unlock();
}
}
return 0;
}
static UINT Thread2Proc(LPVOID)
{
boolean b;
do {
mut.Lock();
b = CanStartStep2;
mut.Unlock();
} while (!b);
for (int i = 0; i < 100; i++)
{
}
return 0;
}
You can see that when you need to access the shared variable you always have to work explicitly with a mutex. This article explains a simple, yet powerfull way to use variables without explicit uses of mutexes. It's pretty useful when dealing with any type of global application state variables, etc..
To achieve this functionallity, i've implemented a small templated class MutexVar<typename T>
wrapping up these concepts.
The previous example can be rewritten, cleaning up all the explicit mutex Lock()
and Unlock()
calls:
MutexVar<boolean> CanStartStep2 = false;
static UINT Thread1Proc(LPVOID)
{
for (int i = 0; i < 50000; i++)
{
if (i == 10)
CanStartStep2 = true;
}
return 0;
}
static UINT Thread2Proc(LPVOID)
{
while (!CanStartStep2)
;
for (int i = 0; i < 100; i++)
{
}
return 0;
}
Using the code
It's easy to use the code, just follow these steps:
Include the header file:
#include "MutexVar.h"
Declare a variable (e.g. a mutexed int
variable):
MutexVar<int> i = 0;
Start using it like any other int
, e.g.:
i = 100;
int j = i * 2;
cout << i << endl;
Conclusions
I hope this article can help you develop shorter, more efficient and more reusable code. That's all, folks!
Bugs
- Some operators don't work (++, --, amongst others);
- All functions using va_args (
printf
, etc.) need an explicit cast to read a variable value, or else will use variable memory address (thanks walker_andrew_b);
- I'm pretty sure there are some more bugs i haven't found...
History
Version 0.1.0: 17/05/2003
Rui Lopes is doing a Post-Graduation on Digital Talking Books and does some research on Human Computer Interaction and Multimedia at the Faculty of Sciences, University of Lisbon, Portugal.