Several Synchronization Methods (mutex, semaphore, event, critical section)

Source: Internet
Author: User
Design goals:

Simulate a ticket sales system with two threads available for sale, with a total of 100 tickets.
Print the sales information in the middle.
The ticket here is a critical resource,
The console is also a critical resource. (If both outputs cause confusion on the screen)

Original program:

# Include <stdio. h>
# Include <iostream>
# Include <windows. h>

Using namespace STD;

Int Total = 100;

DWORD winapi proc1 (
Lpvoid lpparameter // thread data
){
While (1 ){
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread1 sold:" <total -- <Endl;
}
Return 0;
};

DWORD winapi proc2 (
Lpvoid lpparameter // thread data
){
While (1 ){
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread2 sold:" <total -- <Endl;
}
Return 0;
};

Int main (){
Handle thread1, thread2;
Thread1 = createthread (null, 0, proc1, null, 0, null );
Thread2 = createthread (null, 0, proc2, null, 0, null );
Sleep (4000 );
Closehandle (thread1 );
Closehandle (thread2 );
Return 0;
}

The program has two threads.
Determine whether the number of votes is 0,
If not, a ticket is sold and the ticket number is printed.

The random delay of the center marked with red is a key point.
If he is removed, the effect is generally invisible.
Because the computer is too fast, if judgment and the following output,
Almost completed at the same time.
In the sense of time slice, most of the time can be seen as atomic operations.
After the thread is reduced to 0, the thread stops normally.
Therefore, a random delay is given to force the separation of if judgment and total,
In this way, we can see the problems caused by the lack of synchronization.

The output of this program may be character crossover in some places, which is confusing.
The most obvious thing is that after the value is reduced to 0, it will be continuously reduced to the following.

Synchronization framework:

The following methods are similar,
The basic process is:

1. Define related variables
2. Create related variables
3. Wait for related signals before entering the critical section
4. Clear related signals when exiting
(Sometimes the signal can enter the critical section, or when the signal is not available,
There are different descriptions in several implementation methods, so clearing is a general statement)

Mutex:

# Include <stdio. h>
# Include <iostream>
# Include <windows. h>

Using namespace STD;

Int Total = 100;
Handle mutex;

DWORD winapi proc1 (
Lpvoid lpparameter // thread data
){
While (1 ){
Waitforsingleobject (mutex, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread1 sold:" <total -- <Endl;
Releasemutex (mutex );
}
Return 0;
};

DWORD winapi proc2 (
Lpvoid lpparameter // thread data
){
While (1 ){
Waitforsingleobject (mutex, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread2 sold:" <total -- <Endl;
Releasemutex (mutex );
}
Return 0;
};

Int main (){
Handle thread1, thread2;
Mutex = createmutex (null, false, null );
Thread1 = createthread (null, 0, proc1, null, 0, null );
Thread2 = createthread (null, 0, proc2, null, 0, null );
Sleep (4000 );
Closehandle (thread1 );
Closehandle (thread2 );
Closehandle (mutex );
Return 0;
}

This is the most basic and very consistent with the Framework,
Just write the functions marked with red in this way.

Semaphores:

# Include <stdio. h>
# Include <iostream>
# Include <windows. h>

Using namespace STD;

Int Total = 100;

Handle semaphore;

DWORD winapi proc1 (
Lpvoid lpparameter // thread data
){
While (1 ){
Waitforsingleobject (semaphore, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread1 sold:" <total -- <Endl;
Releasesemaphore (semaphore, 1, null );
}
Return 0;
};

DWORD winapi proc2 (
Lpvoid lpparameter // thread data
){
While (total> 0 ){
Waitforsingleobject (semaphore, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread2 sold:" <total -- <Endl;
Releasesemaphore (semaphore, 1, null );
}
Return 0;
};

Int main (){
Handle thread1, thread2;
Semaphore = createsemaphore (null, 1, 1, null );

Thread1 = createthread (null, 0, proc1, null, 0, null );
Thread2 = createthread (null, 0, proc2, null, 0, null );

Sleep (4000 );
Closehandle (thread1 );
Closehandle (thread2 );
Closehandle (semaphore );

Return 0;
}

Unlike mutex, semaphores allow simultaneous access by multiple threads.
For example, in the writer/Reader Model, simultaneous access by multiple readers is allowed.
During creation, you can specify the maximum number and initial number.
If it is set to 1, this is the case used here. It is equivalent to the previous mutex method.

Event:

# Include <stdio. h>
# Include <iostream>
# Include <windows. h>

Using namespace STD;

Int Total = 100;

Handle event;

DWORD winapi proc1 (
Lpvoid lpparameter // thread data
){
While (1 ){
Waitforsingleobject (event, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread1 sold:" <total -- <Endl;
Setevent (event );
}
Return 0;
};

DWORD winapi proc2 (
Lpvoid lpparameter // thread data
){
While (total> 0 ){
Waitforsingleobject (event, infinite );
If (Total = 0) break;
Sleep (RAND () % 30 );
Cout <"thread2 sold:" <total -- <Endl;
Setevent (event );
}
Return 0;
};

Int main (){
Handle thread1, thread2;
Event = createevent (null, false, true, null );
Thread1 = createthread (null, 0, proc1, null, 0, null );
Thread2 = createthread (null, 0, proc2, null, 0, null );
Sleep (4000 );
Closehandle (thread1 );
Closehandle (thread2 );
Closehandle (event );
Return 0;
}

The second parameter of createevent is to set whether it is a manual event.
If it is manual, when waitforsingleobject is used to wait for the event,
The system does not clear the signals that have occurred in this event,
Therefore, you need to call resetevent to clear it.
The gap between the two functions will cause potential synchronization problems.
Therefore, false is set to indicate automatic events.
When this event occurs, the event is set to invalid to prevent other places from entering the critical segment.

Critical section:

# Include <stdio. h>
# Include <iostream>
# Include <windows. h>

Using namespace STD;

Int Total = 100;

Critical_section _ Cs;

DWORD winapi proc1 (
Lpvoid lpparameter // thread data
){
While (1 ){
Entercriticalsection (& _ CS );
If (Total = 0) break;
// Sleep (RAND () % 30 );
Cout <"thread1 sold:" <total -- <Endl;
Leavecriticalsection (& _ CS );
}
Return 0;
};

DWORD winapi proc2 (
Lpvoid lpparameter // thread data
){
While (1 ){
Entercriticalsection (& _ CS );
If (Total = 0) break;
// Sleep (RAND () % 30 );
Cout <"thread2 sold:" <total -- <Endl;
Leavecriticalsection (& _ CS );
}
Return 0;
};

Int main (){
Handle thread1, thread2;
Initializecriticalsection (& _ CS );
Thread1 = createthread (null, 0, proc1, null, 0, null );
Thread2 = createthread (null, 0, proc2, null, 0, null );
Sleep (4000 );
Closehandle (thread1 );
Closehandle (thread2 );
Return 0;
}

Compared with the previous one, this method does not require operations such as closehandle at the end.

I also noted that I commented out the above sleep.
Because the key section is used for synchronization, the speed is very fast and the resource consumption is smaller than the previous several.
After the random delay is added, a thread may sell the ticket directly ..

Even in the current writing, it may run several times,
You can find information that contains several thread2 information or vice versa.

But observe the first three methods. Basically, the result is a thread output, which is intertwined frequently.

Summary:

The first three methods depend on a handle,
They can all specify a name to become a global object,
Synchronization between processes can be completed.
Destroy related handles when you do not need them.
Resource consumption is relatively large.

The last critical section consumes a very small amount of resources and is fast.
However, synchronization between threads can only be solved.

Link: http://hplonline20100103.blog.163.com/blog/static/1361364342010040040921/

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.