See Msdn:http://msdn.microsoft.com/en-us/library/windows/desktop/ms686903%28v=vs.85%29.aspx for details
As we have seen, you can use Srwlock when you want the writer thread and the reader thread to access a resource in exclusive or shared ways. In these cases, if the reader thread has no data to read, it should release the lock and wait until the writer thread has produced new data. If the data structure that is used to receive the writer thread is full, the writer should also release Srwlock and go to sleep until the thread is read to clear the structure.
We want the thread to release the lock in an atomic manner and block itself until a certain condition is established. It is more complicated to implement such a thread synchronization. Windows provides a condition variable to help us do this by Sleepconditionvariablecs (critical section) or the SLEEPCONDITIONVARIABLESRW function.
When the thread detects that the appropriate condition is satisfied (for example, there is data for the reader to use), it calls Wakeconditionvariable or wakeallconditionvariable, so that the thread that blocks in the sleep* function is awakened.
Take a look at the code first:
[CPP]View Plaincopy
- //Condition variable. CPP: The entry point that defines the console application.
- //
- #include "stdafx.h"
- #include <windows.h>
- #include <iostream>
- #include <vector>
- #include <process.h>
- using namespace std;
- DWORD WINAPI threadproduce (PVOID pvparam);
- DWORD WINAPI ThreadUser1 (PVOID pvparam);
- DWORD WINAPI ThreadUser2 (PVOID pvparam);
- vector<int> Ivec;
- SRWLOCK G_lock;
- SRWLOCK G_lock2;
- Condition_variable G_conditionvar;
- int _tmain (int argc, _tchar* argv[])
- {
- Initializesrwlock (&g_lock); //Initialize lock
- //Create producer
- HANDLE hThread1 = (HANDLE) _beginthreadex (null,0, ( unsigned int(_stdcall *) ( void *)) threadproduce,null,0,0);
- //Create reader thread
- HANDLE hThread2 = (HANDLE) _beginthreadex (null,0, (unsigned int(_stdcall * ) (void*)) threaduser1,null,0,0);
- HANDLE hThread3 = (HANDLE) _beginthreadex (null,0, ( unsigned int(_stdcall *) ( void *)) threaduser2,null,0,0);
- CloseHandle (HTHREAD1);
- CloseHandle (HTHREAD2);
- CloseHandle (HTHREAD3);
- System ("pause");
- return 0;
- }
- DWORD WINAPI threadproduce (PVOID pvparam)
- {
- for (int i=0; i<10; ++i)
- {
- Acquiresrwlockexclusive (&g_lock); //Get SRW lock
- Ivec.push_back (i);
- Releasesrwlockexclusive (&g_lock); //Release SRW lock
- Wakeconditionvariable (&g_conditionvar); //Because, after each execution of the push_back, there must be at least one element in the container (producer
- //produce something) the thread that is blocking in the sleep* is awakened (the thread that reads the sleep).
- Sleep (1000); //Stop, let the reader read first if not wait, may lead to vector empty before pop error
- }
- return 0;
- }
- DWORD WINAPI ThreadUser1 (PVOID pvparam)
- {
- while (1)
- {
- Acquiresrwlockexclusive (&g_lock);
- while (Ivec.empty ())
- {
- cout<<"Waiting to be written"<<endl;
- //If the container is empty, that is, no content can be read, then let the thread go to sleep until wakeconditionallvariable (&g_conditionvar) is called;
- SLEEPCONDITIONVARIABLESRW (&g_conditionvar,&g_lock,infinite,condition_variable_lockmode_shared);
- }
- cout<<"Thread 1:"<<ivec.back () <<endl;
- Ivec.pop_back ();
- Releasesrwlockexclusive (&g_lock);
- }
- return 0;
- }
- DWORD WINAPI ThreadUser2 (PVOID pvparam)
- {
- while (1)
- {
- Acquiresrwlockexclusive (&g_lock);
- while (Ivec.empty ())
- {
- cout<<"Waiting to be written"<<endl;
- SLEEPCONDITIONVARIABLESRW (&g_conditionvar,&g_lock,infinite,condition_variable_lockmode_shared);
- }
- cout<<"Thread 2:"<<ivec.back () <<endl;
- Ivec.pop_back ();
- Releasesrwlockexclusive (&g_lock);
- }
- return 0;
- }
Analyzing this code is very simple and can be seen in code annotations. Before, there were a few mistakes in writing this code:
(1) Differences between functions of acquiresrwlockexclusive () releasesrwlockexclusive () and Accquiresrwlockshare () Releasesrwlockshare () two
The former obtains exclusive access to the protected resources while the latter obtains the shared access to protect the resources, because although the read thread in the code, while reading the data, he also pop_back () the contents of the container, that is, can be regarded as "write", because we have to obtain exclusive access.
(2) The difference between Wakeconditionvariabel () and wakeallconditionvariable ():
When the former is called, a thread that waits for the same condition variable to be triggered in the sleepconditionvariable* function is locked and returned. When this thread releases the same lock, it does not wake up other threads that are waiting for the same condition variable
When the latter is called, it causes one or more threads in the sleepconditionvariable* function to wait for the condition variable to trigger access to the resource and return.
(3)
SLEEPCONDITIONVARIABLESRW ( __in_out conditionvariable,/ /thread sleep-related condition variable __in_out SRWLock, // Point to a srwlock pointer __in dwmilliseconds,//desired time to wait, can be infinite __in Flags);
The function performs two operations in the same way as an atomic operation:
1. Release the lock that the srwlock points to;
2. Put the thread to sleep.
If the parameter flags is condition_variable_lockmode_shared, multiple reader threads can be allowed to lock at the same time.