Click here to Skip to main content
13,150,178 members (58,022 online)
Click here to Skip to main content
Add your own
alternative version

Stats

24.6K views
157 downloads
9 bookmarked
Posted 29 Dec 2013

Scope Lock

, 7 May 2010
Rate this:
Please Sign up or sign in to vote.
A class that will ease building thread-safe classes.
This is an old version of the currently published article.

Introduction

The code that I'll be presenting is really simple, but I found it quite useful.

Background

Not on rare occasions, I had to deal with multi-threading access to resources; that meant locking the resources somehow, either with a mutex or a simple bool that was acting like a semaphore. Thread safety is easy to implement, but... it can be easier!

Usually, you will directly use the functionality that the Win32 API provides through InitializeCriticalSection, EnterCriticalSection, TryEnterCriticalSection, LeaveCriticalSection, and DeleteCritcalSection. With this, you are in control! But you know, "with great power comes great responsibility", so most probably you'll face the same problems I did when it comes to writing medium-sized thread safe classes, especially if some of the methods are quite big and with multiple return points.

For example:

int MyClass::myMethod()
{
    EnterCriticalSection(&cs);

    if (something)
    {
        // Do some access
        LeaveCriticalSection(&cs);    // I don't like that
        return -1;
    }
    else
    {
        // Do some other access
        LeaveCriticalSection(&cs);    // That also...
        return 1;
    }

    // Maybe do something here?

    LeaveCriticalSection(&cs);
    return 0;
}

Doesn't seem right, does it?

Using the code

So, how is my piece of code going to improve this? Well, take a look at the following code:

int MyClass::myMethod()
{
    scope_lock my_lock(cs);

    if (something)
    {
        // Do some access
        return -1;
    }
    else
    {
        // Do some other access
        return 1;
    }

    // Maybe do something here?

    return 0;
}

What you additionally need to do is add cs as a property for your class of type CRITICAL_SECTION and initialize it in the constructor with InitializeCriticalSection and release it in the destructor with DeleteCriticalSection, like you would normally do.

For my classes, I also use a macro, something like this:

#ifdef THREAD_SAFE_MY_CLASS
#    include "windows.h"
#    include "scope_lock.h"
#    define LOCK_MY_CLASS scope_lock my_scope_lock(cs);
#else
#    define LOCK_MY_CLASS ;
#endif

This allows me to just write LOCK_MY_CLASS in the beginning of my functions, and that's it; if I want to compile the class with multithread support, I just define THREAD_SAFE_MY_CLASS; if not, I just leave it like it is (MY_CLASS being just a custom name).

For the record, you also have scope_lock::release(); to release the mutex sooner and scope_lock::engage(); to take it back.

Playing in the global scope

Here's a sample on playing with out it in the global scope:

#include <iostream>

#include "windows.h"
#include "process.h"

using namespace std;

//CRITICAL_SECTION critical_cout;

int z;        // thread counter

void th1(void *)
{
    // print 10 times th1
    for (int i = 0; i < 10; ++i)
        cout << "th1" << endl;

    z--;
}

void th2(void *)
{
    // print 10 times th2
    for (int i = 0; i < 10; ++i)
        cout << "th2" << endl;

    z--;
}

int main(int argc, char *argv[])
{
    //InitializeCriticalSection(&critical_cout);

    z = 2;

    _beginthread(th1, 0, 0);
    _beginthread(th2, 0, 0);

    while (z != 0) Sleep(100);

    //DeleteCriticalSection(&critical_cout);

    return 0;
}

And here's the output on my system:

th1th2

th2th1
th2

th2th1

th2th1

th2th1

th2th1

th2th1

th2th1

th2th1

th1

Now, replacing this:

for (int i = 0; i < 10; ++i)
    cout << "th2" << endl;

with:

for (int i = 0; i < 10; ++i)
{
    scope_lock x(critical_cout);
    cout << "th2" << endl;
}

and uncommenting the cs declaration, the initialization, and the deletion, we get the following result:

th1
th2
th1
th2
th1
th2
th1
th2
th1
th2
th1
th2
th1
th2
th1
th2
th1
th2
th1
th2

Well, that's it. An example using a class, including this example, is found at the top of the page for download. Note the fact that you need to override the copy and the assign constructor for the class if you're going to use them, since you don't want to copy the CRITICAL_SECTION structure (which will get destroyed twice anyhow and will raise an exception).

How it works

The concept behind this is really simple, it makes use of C++ :) We're just entering the critical section in the constructor and leaving it in the destructor.

Hope it helps.

License

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

Share

About the Author

Razvan C. Cojocariu
Software Developer
Romania Romania
No Biography provided

You may also be interested in...

Comments and Discussions

Discussions on this specific version of this article. Add your comments on how to improve this article here. These comments will not be visible on the final published version of this article.
 
QuestionCSingleLock? Pin
DanBaker27-Feb-07 12:13
memberDanBaker27-Feb-07 12:13 
AnswerRe: CSingleLock? Pin
Razvan C. Cojocariu27-Feb-07 20:01
memberRazvan C. Cojocariu27-Feb-07 20:01 
QuestionWhat about ACE or any other library? Pin
oleg54227-Feb-07 4:29
memberoleg54227-Feb-07 4:29 
AnswerRe: What about ACE or any other library? Pin
Razvan C. Cojocariu27-Feb-07 6:48
memberRazvan C. Cojocariu27-Feb-07 6:48 
GeneralExceptions safe Pin
Andrew aka Manik26-Feb-07 22:38
memberAndrew aka Manik26-Feb-07 22:38 
GeneralRe: Exceptions safe Pin
Razvan C. Cojocariu26-Feb-07 22:50
memberRazvan C. Cojocariu26-Feb-07 22:50 

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.


Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170924.2 | Last Updated 7 May 2010
Article Copyright 2013 by Razvan C. Cojocariu
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid