基本是按照书抄的,验证一下
1.利用Interlocked序列函数,原子同步
俩个线程,不停的对gl_num进行修改,gl_num = 5 认为是未加锁的状态,6是加锁状态
调用InterlockedExchange(&gl_num, 6)以后:
- 返回的值是5,表明是该线程拿到了“锁”,可以执行代码,同时执行完成后置为5.
- 返回的不是5,而是6,则说明这个线程未拿到锁,需要sleep。等拿到锁的释放后再次竞争。
#include <Windows.h>
#include <iostream>
#include <process.h>
using namespace std;
long gl_num = 5;
unsigned int __stdcall threadProc(void *p) {
int id = int(p);
while (true) {
if (InterlockedExchange(&gl_num, 6) == 5) {
cout << "thread " << id << " is running.." << endl;
InterlockedExchange(&gl_num, 5);
}
else {
Sleep(0);
}
}
return 0;
}
int main() {
HANDLE hthread1 = (HANDLE)_beginthreadex(NULL, 0, threadProc, (void*)1, 0, NULL);
HANDLE hthread2 = (HANDLE)_beginthreadex(NULL, 0, threadProc, (void*)2, 0, NULL);
WaitForSingleObject(hthread1, INFINITE);
WaitForSingleObject(hthread2, INFINITE);
CloseHandle(hthread1);
CloseHandle(hthread2);
return 0;
}
2.临界区
#include <Windows.h>
#include <iostream>
#include <process.h>
using namespace std;
CRITICAL_SECTION cs;
unsigned int __stdcall threadProc(void *p) {
int id = int(p);
while (true) {
EnterCriticalSection(&cs);
EnterCriticalSection(&cs);
cout << "thread " << id << " is running.." << endl;
LeaveCriticalSection(&cs);
LeaveCriticalSection(&cs);
}
return 0;
}
int main() {
InitializeCriticalSection(&cs);
HANDLE hthread1 = (HANDLE)_beginthreadex(NULL, 0, threadProc, (void*)1, 0, NULL);
HANDLE hthread2 = (HANDLE)_beginthreadex(NULL, 0, threadProc, (void*)2, 0, NULL);
WaitForSingleObject(hthread1, INFINITE);
WaitForSingleObject(hthread2, INFINITE);
CloseHandle(hthread1);
CloseHandle(hthread2);
DeleteCriticalSection(&cs);
return 0;
}
临界区是可以重入的,保证enter和leave次数一样。
windows核心编程指出:如果关键段被另外一个线程占用,则enter会将线程切换到等待状态,即从用户模式进入内核模式(1000个cpu周期),开销很大。
此时可以使用关键段和自旋锁。
3. slim读写锁
using namespace std;
SRWLOCK lock;
unsigned int __stdcall threadProc_read(void *p) {
int id = int(p);
while (true) {
AcquireSRWLockShared(&lock);
cout << "thread read " << id << " is running.." << endl;
ReleaseSRWLockShared(&lock);
Sleep(10);
}
return 0;
}
unsigned int __stdcall threadProc_write(void* p) {
int id = int(p);
while (true) {
AcquireSRWLockExclusive(&lock);
cout << "thread write " << id << " is running.." << endl;
ReleaseSRWLockExclusive(&lock);
Sleep(10);
}
return 0;
}
int main() {
InitializeSRWLock(&lock);
HANDLE hthread1 = (HANDLE)_beginthreadex(NULL, 0, threadProc_read, (void*)1, 0, NULL);
HANDLE hthread2 = (HANDLE)_beginthreadex(NULL, 0, threadProc_read, (void*)2, 0, NULL);
HANDLE hthread3 = (HANDLE)_beginthreadex(NULL, 0, threadProc_write, (void*)3, 0, NULL);
HANDLE hthread4 = (HANDLE)_beginthreadex(NULL, 0, threadProc_write, (void*)4, 0, NULL);
WaitForSingleObject(hthread1, INFINITE);
WaitForSingleObject(hthread2, INFINITE);
WaitForSingleObject(hthread3, INFINITE);
WaitForSingleObject(hthread4, INFINITE);
//这里不closehandle了
return 0;
}
exclusive是独占锁(写锁),shared是共享锁(读锁)。运行结果可见1,2会同时运行,3,4则不会。
验证:
1.一个线程获取了读锁以后,自己和其他线程可以重入获取读锁,但自己不能重入获取写锁,其他线程也不能获取写锁
2.一个线程拿到写锁以后,自己也不能再拿到读锁。当然其他线程也都拿不到读,写锁
4. 条件变量
CONDITION_VARIABLE cv;
CRITICAL_SECTION cs;
unsigned int __stdcall threadProc_read(void *p) {
int id = int(p);
SleepConditionVariableCS(&cv, &cs, INFINITE);
cout << "thread " << id << " running..." << endl;
return 0;
}
unsigned int __stdcall threadProc_write(void* p) {
int id = int(p);
auto t = 10;
while (t--) {
cout << "thread " << id << " running.." << endl;
Sleep(10);
}
WakeAllConditionVariable(&cv);
return 0;
}
int main() {
InitializeCriticalSection(&cs);
InitializeConditionVariable(&cv);
HANDLE hthread1 = (HANDLE)_beginthreadex(NULL, 0, threadProc_read, (void*)1, 0, NULL);
HANDLE hthread2 = (HANDLE)_beginthreadex(NULL, 0, threadProc_write, (void*)2, 0, NULL);
WaitForSingleObject(hthread1, INFINITE);
WaitForSingleObject(hthread2, INFINITE);
return 0;
}