Try to implement Java's synchronized keyword in C + +

Source: Internet
Author: User

In Java, there is a very powerful keyword called synchronized, you can easily implement thread synchronization. Today is a whimsical attempt to emulate a similar one in C + +.

Recently in the study of C + + STL, see smart Pointer This chapter, all sigh with the rich characteristics of language, to achieve a variety of ingenious ideas. The most classic is to use the Stack object construction/destructor to maintain the initialization and release of local resources. According to this ingenious method, leaf out himself to write one, to implement the local code thread synchronization.

There are two forms of synchronized in Java, one is based on functions and the other is chunks. The former is limited by the syntax of C + + and is estimated to be impossible, so try the latter.
Block-level syntax is simple:

Synchronized (syncobject) {    //code}

  
Because all Java variables inherit from object, any variable can be used as a lock. This is not easy to implement in C + +, so we use a specific type instance as a synchronous variable.
Start with the most classic simple synchronization class.

struct Lock:critical_section {    Lock () {        :: InitializeCriticalSection (this);    }    ~lock () {        ::D eletecriticalsection (this);    }    void Enter () {        :: EnterCriticalSection (this);    }    void Leave () {        :: LeaveCriticalSection (this);    }};

This is the most common encapsulation of thread synchronization implemented under Windows. Simply declare a lock instance and call enter and leave before and after the code that needs to be synchronized.
Since it's so easy to use, why continue to improve? Obviously there is a big flaw in this approach, and if you forget to call leave, or Return/throw exit before the call, it will cause a deadlock.
So, we need a mechanism like auto_ptr to automatically maintain the creation and deletion of stack data. Let's call it _auto_lock.

struct _auto_lock {    lock& _lock;    _auto_lock (lock& Lock): _lock (lock) {        _lock. Enter ();    }    ~_auto_lock () {        _lock. Leave ();    }};

_auto_lock is initialized by referencing a lock instance and immediately locks the critical section, and releases the lock when it is destroyed.

With this mechanism, we no longer have to worry about forgetting to call. Leave (). Simply provide a lock object to automatically lock and unlock the current block. There's no need to worry about deadlocks anymore.

Lock Mylock; void Test () {    //Code1     ... Syn code    {        _auto_lock x (mylock);    }     Code2 ...}


After entering the "{" of SYN Code, the _auto_lock is constructed, and the destructor is called regardless of the "}" in that way.
The above code is similar in both STL and boost and is common. Using the construction/destructor of the stack object to maintain local resources is a very common technique for C + +.
Our goal is one step closer. The following starts with the classic macro definition, creating a synchronized syntax sugar that eventually implements the syntax:

Lock Mylock; void Test () {    //Code1     ... Synchronized (Mylock)    {        //sync code    }     //Code2 ...}

Obviously need a called synchronized macro, and define the _auto_lock inside.

#define SYNCHRONIZED (lock) ...        _auto_lock x (Lock) ...

At first glance the syntax is much like a loop, and the variable is defined within the loop, so use for (;;) The structure is no better.

for (_auto_lock x (mylock);;)

But sync code we only need to execute once, so we need another variable to control the number of times. Since for only one type of variable can be declared in a for, we have another layer of loops outside:

for (int _i=0, _i<1; _i++) for (_auto_lock x (mylock); _i<1; _i++)

The synchronized macro replaces the Mylock with the above code, without violating the syntax and implementing the same process. Thanks to the cyclic syntax, you can even use break to jump out of the sync block within synchronized !

  
Let's sort out the above code and do a simple test.

#include <stdio.h> #include <windows.h> #include <process.h>struct lock:critical_section {Lock () {    :: InitializeCriticalSection (this);    } ~lock () {::D eletecriticalsection (this);    } void Enter () {:: EnterCriticalSection (this);    } void Leave () {:: LeaveCriticalSection (this);    }};struct _auto_lock {lock& _lock; _auto_lock (lock& Lock): _lock (lock) {_lock.    Enter (); } ~_auto_lock () {_lock.    Leave (); }}; #define synchronized (lock) for (int _i=0, _i<1; _i++) for (_auto_lock lock# #_x (lock); _i<1; _i++)//---------    -Demo----------lock mylock;//----------test1----------void waittest (int id) {printf ("no.%d waiting...\n", id);    Synchronized (Mylock) {Sleep (1000); } printf ("no.%d done\n", id);}    void Test1 () {_beginthread ((void (__cdecl*) (void*)) waittest, 0, (void*) 1);    _beginthread ((Void (__cdecl*) (void*)) waittest, 0, (void*) 2); _beginthread (void (__cdecl*) (void*)) waittest, 0, (void*) 3);}    ----------test2----------void throwfunc (int id) {printf ("no.%d waiting...\n", id);        Synchronized (Mylock) {Sleep (1000);    Throw "Some err"; } printf ("no.%d done\n", id);}    void throwtest (int id) {try {throwfunc (ID);    } catch (...)    {printf ("%d excepted\n", id);    }}void Test2 () {_beginthread ((void (__cdecl*) (void*)) throwtest, 0, (void*) 1);    _beginthread ((Void (__cdecl*) (void*)) throwtest, 0, (void*) 2); _beginthread ((Void (__cdecl*) (void*)) throwtest, 0, (void*) 3);}    ----------test3----------void breaktest (int id) {printf ("no.%d waiting...\n", id);        Synchronized (Mylock) {Sleep (1000);        Break    Sleep (99999999); } printf ("no.%d done\n", id);}    void Test3 () {_beginthread ((void (__cdecl*) (void*)) breaktest, 0, (void*) 1);    _beginthread ((Void (__cdecl*) (void*)) breaktest, 0, (void*) 2); _beginthread ((Void (__cdecl*) (void*)) breaktest, 0, (void*) 3);} int main (iNT ARGC, char* argv[]) {printf ("Wait Test. Press any key to start...\n");    GetChar ();    Test1 ();    GetChar ();    printf ("Exception Test Press any key to start...\n");    GetChar ();    Test2 ();    GetChar ();    printf ("Break Test. Press any key to start...\n");    GetChar ();    Test3 ();    GetChar (); return 0;}

  

In addition to the use of syntactic sugar, one of the most important features is that you can use break in the synchronized synchronization block to jump out, and do not cause deadlocks, which is not possible by other methods.

Try to implement Java's synchronized keyword in C + +

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.