Synchronization between threads and processes

Source: Internet
Author: User

Critical Section

The critical section is the simplest synchronization object, which can only be used within the same process. It ensures that only one thread can apply for this object.
Void initializecriticalsection (maid ); Critical Section
Void deletecriticalsection (maid section ); Delete critical section
Void entercriticalsection (maid section ); Entering the critical section is equivalent to applying for locking. If the critical section is being used by another thread, the function will wait for other threads to release.
Bool tryentercriticalsection (maid section ); Entering the critical section is equivalent to applying for locking. Unlike entercriticalsection, if the critical section is being used by another thread, the function returns false immediately without waiting.
Void leavecriticalsection (maid section ); Exit the critical section, which is equivalent to applying for unlocking

The following sample code demonstrates how to use the critical section for Data Synchronization:

// Global variable
Int icounter = 0;
Critical_section cricounter;

DWORD threada (void * PD)
{
Int IID = (INT) PD;
For (INT I = 0; I <8; I ++)
{
Entercriticalsection (& cricounter );
Int icopy = icounter;
Sleep (100 );
Icounter = icopy + 1;
Printf ("thread % d: % d/N", IID, icounter );
Leavecriticalsection (& cricounter );
}
Return 0;
}
// In Main Function
{
// Create a critical section
Initializecriticalsection (& cricounter );
// Create a thread
Handle hthread [3];
Cwinthread * pt1 = afxbeginthread (afx_threadproc) threada, (void *) 1 );
Cwinthread * pt2 = afxbeginthread (afx_threadproc) threada, (void *) 2 );
Cwinthread * pt3 = afxbeginthread (afx_threadproc) threada, (void *) 3 );
Hthread [0] = pt1-> m_hthread;
Hthread [1] = pt2-> m_hthread;
Hthread [2] = pt3-> m_hthread;
// Wait until the thread ends
// The usage of waitformultipleobjects will be discussed later.
Waitformultipleobjects (3, hthread, true, infinite );
// Delete the critical section
Deletecriticalsection (& cricounter );
Printf ("/nover/N ");
}

 

Mutex

 

The mutex function is similar to that of the critical section, but the mutex can be named, that is, it can be used across processes. Therefore, creating mutex requires more resources. Therefore, if you only use it within a process, using the critical section will bring speed advantages and reduce resource occupation. Because the mutex is a cross-process mutex. Once created, you can open it by name.
Create mutex:
Handle createmutex (
Lpsecurity_attributes lpmutexattributes, // Security Information
Bool binitialowner, // initial status,
// If it is set to true, it indicates that the thread that created it directly owns the mutex and does not need to apply for it again.
Lptstr lpname // name, which can be null, but cannot be opened by other threads/processes.
);
Open an existing mutex:
Handle openmutex (
DWORD dwdesiredaccess, // access method
Bool binherithandle, // whether it can be inherited
Lptstr lpname // name
);
Release the right to use mutex, but the thread that calls the function must have the right to use the mutex:
Bool releasemutex (// act as leavecriticalsection
Handle hmutex // handle
);
Disable mutex:
Bool closehandle (
Handle hobject // handle
);
If the mutex is in use, it is in the non-signal state. After the mutex is released, it becomes in the signal state. After the waiting is successful, the waitforsingleobject function sets the mutex to the non-signal state, so that other threads cannot obtain the permission and need to continue waiting. The waitforsingleobject function also supports queuing to ensure that the thread waiting for the request first obtains the right to use the object.

Int icounter = 0;

DWORD threada (void * PD)
{
Int IID = (INT) PD;
// Re-open it internally
Handle hcounterin = openmutex (mutex_all_access, false, "Sam SP 44 ");

For (INT I = 0; I <8; I ++)
{
Printf ("% d wait for Object/N", IID );
Waitforsingleobject (hcounterin, infinite );
Int icopy = icounter;
Sleep (100 );
Icounter = icopy + 1;
Printf ("/T/tthread % d: % d/N", IID, icounter );
Releasemutex (hcounterin );
}
Closehandle (hcounterin );
Return 0;
}

// In Main Function
{
// Create mutex
Handle hcounter = NULL;
If (hcounter = openmutex (mutex_all_access, false, "Sam SP 44") = NULL)
{
// If no other process creates this mutex, recreate it.
Hcounter = createmutex (null, false, "Sam SP 44 ");
}

// Create a thread
Handle hthread [3];
Cwinthread * pt1 = afxbeginthread (afx_threadproc) threada, (void *) 1 );
Cwinthread * pt2 = afxbeginthread (afx_threadproc) threada, (void *) 2 );
Cwinthread * pt3 = afxbeginthread (afx_threadproc) threada, (void *) 3 );
Hthread [0] = pt1-> m_hthread;
Hthread [1] = pt2-> m_hthread;
Hthread [2] = pt3-> m_hthread;

// Wait until the thread ends
Waitformultipleobjects (3, hthread, true, infinite );

// Close the handle
Closehandle (hcounter );
}
}

The waitforsingleobject function can act on:
Mutex
Event
Semaphore
Job
Process
Thread
Waitable Timer
Console input
Mutex, semaphore, and event can all be used by a process to synchronize data. Other objects have nothing to do with data synchronization, but for the process and thread, if the process and thread are in the running status, there is no signal, and there is a signal after exiting. So we can use waitforsingleobject to wait for the process and thread to exit. (As for traffic signals, we will talk about the usage of events.) in the previous example, we used the waitformultipleobjects function. This function is similar to waitforsingleobject, but we can see from the name that, waitformultipleobjects will be used to wait for multiple objects to change to a signal state. The function prototype is as follows:
DWORD waitformultipleobjects (
DWORD ncount, // Number of waiting objects
Const handle * lphandles, // object handle array pointer
Bool fwaitall, // wait method,
// If it is set to true, the system returns the result only when all objects are in the signal state. If it is set to false, the system returns the result when any object changes to the signal state.
DWORD dwmilliseconds // timeout setting, in ms. If it is infinite, it indicates an indefinite wait.
);

Dwmilliseconds ranges from 0 to 0x7fffffff or infinite-0 xffffffff.

The returned value indicates:
Wait_object_0 to (wait_object_0 + ncount-1): When fwaitall is true, it indicates that all objects are in a signal state, when fwaitall is false, use the return value minus wait_object_0 to obtain the subscript of the object that is in the signal state in the array.
Wait_abandoned_0 to (wait_abandoned_0 + ncount-1): When fwaitall is true, it indicates that all objects are in a signal state. When fwaitall is false, it indicates that one object in the object is a mutex, the mutex becomes a signal State because it is disabled. Use the return value minus wait_object_0 to get the subscript of the object that changes to a signal state in the array.
Wait_timeout: indicates that the specified time has been exceeded.

 

Signal lamp

 

The signal lamp has an initial value, indicating how many processes/Threads can enter. When the signal lamp value is greater than 0, there is a signal State. If the signal lamp value is less than or equal to 0, there is no signal State. Therefore, waitforsingleobject can be used for waiting, when waitforsingleobject waits for a success, the signal light value is reduced by 1 until it is released, and the signal light is increased by 1. The following APIs are used for traffic signal operations:

Create a traffic signal:
Handle createsemaphore (
Lpsecurity_attributes l1_maphoreattributes, // Security Attribute. null indicates that the default security description is used.
Long linitialcount, // Initial Value
Long lmaximumcount, // maximum value
Lptstr lpname // name
);
Turn on the signal light:
Handle opensemaphore (
DWORD dwdesiredaccess, // access method
Bool binherithandle, // whether it can be inherited
Lptstr lpname // name
);
Release traffic signals:
Bool releasesemaphore (
Handle hsemaphore, // handle
Long lreleasecount, // number of releases to increase the number of traffic signals
Lplong lppreviouscount // used to obtain the signal value before release. It can be null.
);
Turn off the signal light:
Bool closehandle (
Handle hobject // handle
);
DWORD threada (void * PD)
{
Int IID = (INT) PD;
// Re-open it internally
Handle hcounterin = opensemaphore (semaphore_all_access, false, "Sam SP 44 ");

For (INT I = 0; I <3; I ++)
{
Printf ("% d wait for Object/N", IID );
Waitforsingleobject (hcounterin, infinite );
Printf ("/T/tthread % d: Do Database Access Call/N", IID );
Sleep (100 );
Printf ("/T/tthread % d: Do Database Access Call end/N", IID );
Releasesemaphore (hcounterin, 1, null );
}
Closehandle (hcounterin );
Return 0;
}
// In Main Function
{
// Create a signal lamp
Handle hcounter = NULL;
If (hcounter = opensemaphore (semaphore_all_access, false, "Sam SP 44") = NULL)
{
// If no other process creates this signal, recreate it.
Hcounter = createsemaphore (null, 2, 2, "Sam SP 44 ");
}

// Create a thread
Handle hthread [3];
Cwinthread * pt1 = afxbeginthread (afx_threadproc) threada, (void *) 1 );
Cwinthread * pt2 = afxbeginthread (afx_threadproc) threada, (void *) 2 );
Cwinthread * pt3 = afxbeginthread (afx_threadproc) threada, (void *) 3 );
Hthread [0] = pt1-> m_hthread;
Hthread [1] = pt2-> m_hthread;
Hthread [2] = pt3-> m_hthread;
// Wait until the thread ends
Waitformultipleobjects (3, hthread, true, infinite );

// Close the handle
Closehandle (hcounter );
}

A signal lamp is sometimes used as a counter. Generally, the initial value is set to 0. Call releasesemaphore to increase the count, and then use waitforsingleobject to reduce the count, unfortunately, we usually cannot get the current value of the signal lamp, but we can check whether the current value of the signal lamp is 0 by setting the waiting time of waitforsingleobject to 0.

 

Event

 

The event object is used to notify other processes/threads that an operation has been completed, in addition, it is impossible to coordinate tasks at the process tip by waiting for the end of threads in other processes.
An event object can be created in one or two ways. One is automatic resetting. When other threads use waitforsingleobject to wait until the event object changes to a signal, the event object automatically changes to a non-signal state, one is to manually reset the status of the event object in other threads after waitforsingleobject waits until the event object changes to a signal. For example, if multiple threads are waiting for the end of a thread, we can use a manual reset event to set the event to a signal when the waiting thread ends, in this way, the wait for the event by multiple threads will be successful (because the event status will not be automatically reset ). The event-related APIs are as follows:

Create event object:
Handle createevent (
Lpsecurity_attributes lpeventattributes, // Security Attribute. null indicates that the default security description is used.
Bool bmanualreset, // whether it is manually reset
Bool binitialstate, // whether the initial state is in a signal state
Lptstr lpname // name
);
Open event object:
Handle openevent (
DWORD dwdesiredaccess, // access method
Bool binherithandle, // whether it can be inherited
Lptstr lpname // name
);
Set the event to a stateless state:
Bool resetevent (
Handle hevent // handle
);
Set whether the event has a signal status:
Bool setevent (
Handle hevent // handle
);
Close event object:
Bool closehandle (
Handle hobject // handle
);

In MFC, the corresponding classes are provided for various synchronization objects.

These classes encapsulate the object creation, opening, control, and deletion functions described above. However, to use the wait function, you need to use the other two classes: csinglelock and cmultilock. These two classes encapsulate the waitforsingleobject and waitformultipleobjects functions. If you need to understand the definition of these classes, it is easy to understand through the above introduction, however, in terms of Object synchronization, I think it is more intuitive and convenient to use API functions than to use the MFC class.

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.