Windows线程同步的四种方法
来源:互联网 发布:搜狗输入法云计算进程 编辑:程序博客网 时间:2024/05/17 23:01
一、基于CRITICAL_SECTION的同步:
基于CRITICAL_SECTION的同步中将创建并运用"CRITICAL_SECTION对象“, 但这并非内核对象。与其他同步对象相同,它是进入临界区的一把”钥匙“。因此,为了进入临界区,需要得到CRITICAL_SECTION对象这把”钥匙“。离开时需要上交CRITICAL_SECTION对象。
#include <windows.h> //初始化函数原型 VOID InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection // address of critical // section object ); //销毁函数原型 VOID DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection // pointer to critical // section object );
其中lpCriticalSection, 在初始化函数中传入需要初始化的CRITICAL_SECTION对象的地址值,销毁函数中传入需要解除的CRITICAL对象的地址值。
销毁函数并不是销毁CRITICAL_SECTION对象的函数,该函数的作用是销毁CRITICAL_SECTION对象使用过的资源。
#include <window.h> //获取 VOID EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection // pointer to critical // section object ); //释放 VOID LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection // address of critical // section object ); //lpCriticalSection 参数为获取和释放CRITICAL_SECTION对象的地址值。示例程序:
#include <windows.h> #include <stdio.h> #include <process.h> #include <stdlib.h> #define NUM_THREAD 50 unsigned WINAPI threadInc(void * arg); unsigned WINAPI threadDes(void * arg); long long num = 0; CRITICAL_SECTION cs; int main() { HANDLE tHandles[NUM_THREAD]; int i; InitializeCriticalSection(&cs); //初始化临界区 for(i = 0; i < NUM_THREAD; i++) { if(i % 2) tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL); else tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL); } WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE); DeleteCriticalSection(&cs); //释放临界区 printf("result: %lld \n", num); return 0; } unsigned WINAPI threadInc(void * arg) { int i; EnterCriticalSection(&cs); //进入临界区 for(i = 0; i < 50000000; i++) num += 1; LeaveCriticalSection(&cs); //离开临界区 return 0; } unsigned WINAPI threadDes(void * arg) { int i; EnterCriticalSection(&cs); //进入临界区 for(i = 0; i < 50000000; i++) num -= 1; LeaveCriticalSection(&cs); //离开临界区 return 0; }
二、基于互斥量对象的同步:
基于互斥量对象的同步方法与给予CRITICAL_SECTION对象的同步方法类似。
创建互斥量对象的函数:
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, // pointer to security attributes BOOL bInitialOwner, // flag for initial ownership LPCTSTR lpName // pointer to mutex-object name ); //参数意义: //lpMutextAttributes 传递安全相关的配置信息,使用默认安全设置时可以传递NULL //bInitialOwner 如果为TRUE,则创建出的互斥量对象属于调用该函数的线程,同时进入non-signaled状态; // 如果为FALSE,则创建出的互斥量对象不属于任何线程,此时状态为signaled //lpName 用于命名互斥量对象。传入NULL时创建无名的互斥量对象可以看出,如果互斥量对象不属于任何拥有着,则将进入signaled状态,利用该特点进行同步。另外,互斥量属于内核对象,所以通过如下函数销毁:
BOOL CloseHandle( HANDLE hObject //要销毁内核对象的句柄);获取和释放互斥量的函数:
//获取函数 windows线程创建中介绍的此函数,用于针对单个内核对象验证signaled。DWORD WaitForSingleObject( HANDLE hHandle, // handle to object to wait for DWORD dwMilliseconds // time-out interval in milliseconds);//释放互斥量BOOL ReleaseMutex( HANDLE hMutex //需要释放的对象的句柄);
互斥量被某一线程获取时为non-signaled状态,释放时进入signaled状态。因此,可以利用WaitForSingleObject函数验证互斥量是否已分配。互斥量在WaitForSingleObject函数返回时自动进入non-signaled状态,因为它是"auto-reset"模式的内核对象。
#include <windows.h> #include <process.h> #include <stdio.h> #include <stdlib.h> #define NUM_THREAD 50 unsigned WINAPI threadInc(void * arg); unsigned WINAPI threadDes(void * arg); long long num = 0; HANDLE hMutex; int main() { HANDLE tHandles[NUM_THREAD]; int i; hMutex = CreateMutex(NULL, FALSE, NULL); //创建互斥量,此时为signaled状态 for (i = 0; i < NUM_THREAD; i++) { if (i % 2) tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL); else tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL); } WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE); CloseHandle(hMutex); //销毁对象 printf("result: %lld \n", num); return 0; } unsigned WINAPI threadInc(void * arg) { int i; WaitForSingleObject(hMutex, INFINITE); //获取,进入的钥匙 for (i = 0; i < 50000000; i++) num += 1; ReleaseMutex(hMutex); //释放,离开时上交钥匙 return 0; } unsigned WINAPI threadDes(void * arg) { int i; WaitForSingleObject(hMutex, INFINITE); for (i = 0; i < 50000000; i++) num -= 1; ReleaseMutex(hMutex); return 0; }
三、基于信号量对象的同步:
创建与销毁函数:
//创建信号量对象HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // pointer to security attributes LONG lInitialCount, // initial count LONG lMaximumCount, // maximum count LPCTSTR lpName // pointer to semaphore-object name);//参数意义://lpSemaphoreAttributes 安全配置信息,采用默认安全设置时NULL//lInitialCount 指定信号量的初始值,应大于0小于lMaximumCount//lMaximumCount 信号量的最大值。该值为1时,信号量变为只能表示0和1的二进制信号量//lpName 用于命名信号量对象。传递NULL时创建无名的信号量对象//销毁信号量同样使用CloseHandle()函数可以利用“信号量值为0时进入non-signaled状态,大于0时进入signaled状态”的特性进行同步。向lInitialCount参数传递0时,创建non-signaled状态的信号量对象。而向lMaximumCount传入3时,信号量最大值为3,因此可以实现3个线程同时访问临界区时的同步。
释放信号量对象的函数:
//释放信号量BOOL ReleaseSemaphore( HANDLE hSemaphore, // handle to the semaphore object LONG lReleaseCount, // amount to add to current count LPLONG lpPreviousCount // address of previous count);//参数意义://hSemaphore 传递需要释放的信号量对象。//lReleaseCount 释放以为着信号量值的增加,通过该参数可以指定增加的值。超过最大值则不增加,返回FALSE//lpPreviousCount 用于保存之前值得变量地址,不需要是可传递NULL信号量对象大于0时成为signaled对象,为0时成为non-signaled状态。因此,调用WaitForSingleObject函数时,信号量大于0的情况下才会返回。返回的同时将信号量的值减1,同时进入non-signaled状态。
#include <windows.h> #include <process.h> #include <stdio.h> unsigned WINAPI Read(void * arg); unsigned WINAPI Accu(void * arg); static HANDLE semOne; static HANDLE semTwo; static int num; int main(int argc, char *argv[]) { HANDLE hThread1, hThread2; //创建信号量对象,设置为0进入non-signaled状态 semOne = CreateSemaphore(NULL, 0, 1, NULL); //创建信号量对象,设置为1进入signaled状态 semTwo = CreateSemaphore(NULL, 1, 1, NULL); hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL); hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); CloseHandle(semOne); //销毁 CloseHandle(semTwo); //销毁 return 0; } unsigned WINAPI Read(void * arg) { int i; for (i = 0; i < 5; i++) { fputs("Input num: ", stdout); //临界区的开始 signaled状态 WaitForSingleObject(semTwo, INFINITE); scanf("%d", &num); //临界区的结束 non-signaled状态 ReleaseSemaphore(semOne, 1, NULL); } return 0; } unsigned WINAPI Accu(void * arg) { int sum = 0, i; for (i = 0; i < 5; i++) { //临界区的开始 non-signaled状态 WaitForSingleObject(semOne, INFINITE); sum += num; //临界区的结束 signaled状态 ReleaseSemaphore(semTwo, 1, NULL); } printf("Result: %d \n", sum); return 0; }
四、基于事件对象的同步:
事件同步对象与前2种同步方法相比有很大不同,区别在于:该方式下创建对象时,可以在自动non-signaled状态运行的auto-reset模式和与之相反的manual-reset模式中任选其一。而事件对象的主要特点是可以创建manual-reset模式的对象。
创建事件对象的函数:HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // pointer to security attributes BOOL bManualReset, // flag for manual-reset event BOOL bInitialState, // flag for initial state LPCTSTR lpName // pointer to event-object name); 参数说明://lpEventAttributes 安全配置相关参数,采用默认安全配置时传入NULL//bManualReset 传入TRUE时创建manual-reset模式的事件对象,传入FALSE时创建auto-reset模式的事件对象//bInitialState 传入TRUE时创建signaled状态,传入FALSE时创建non-signaled状态的事件对象//lpName 用于命名事件对象。传递NULL时创建无名的事件对象当第二个参数传入TRUE时将创建manual-reset模式的事件对象,此时即使WaitForSingleObject函数返回也不会回到non-signaled状态。因此,在这种情况下,需要通过如下2个函数明确更改对象状态。
BOOL ResetEvent( HANDLE hEvent // to the non-signaled ); BOOL SetEvent( HANDLE hEvent // to the signaled );传递事件对象句柄并希望改为non-signed状态时,应调用ResetEvent函数。如果希望改为signaled状态,则可以调用SetEvent函数。
实例程序:
#include <windows.h> #include <stdio.h> #include <process.h> #define STR_LEN 100 unsigned WINAPI NumberOfA(void *arg); unsigned WINAPI NumberOfOthers(void *arg); static char str[STR_LEN]; static HANDLE hEvent; int main(int argc, char *argv[]) { HANDLE hThread1, hThread2; //以non-signaled创建manual-reset模式的事件对象 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL); hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL); fputs("Input string: ", stdout); fgets(str, STR_LEN, stdin); //读入字符串后改为signaled状态 SetEvent(hEvent); WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hThread2, INFINITE); //non-signaled 如果不更改,对象继续停留在signaled ResetEvent(hEvent); CloseHandle(hEvent); return 0; } unsigned WINAPI NumberOfA(void *arg) { int i, cnt = 0; WaitForSingleObject(hEvent, INFINITE); for (i = 0; str[i] != 0; i++) { if (str[i] == 'A') cnt++; } printf("Num of A: %d \n", cnt); return 0; } unsigned WINAPI NumberOfOthers(void *arg) { int i, cnt = 0; WaitForSingleObject(hEvent, INFINITE); for (i = 0; str[i] != 0; i++) { if (str[i] != 'A') cnt++; } printf("Num of others: %d \n", cnt - 1); return 0; }
阅读全文
0 0
- Windows线程同步的四种方法
- windows线程同步的总结-------四种实现的方法
- windows四种线程同步互斥的控制方法
- windows线程同步的总结-------四种实现的方法blogdown整理
- windows 线程同步的4种方法
- windows 线程同步的4种方法
- windows 线程同步的4种方法
- windows线程同步的几种方法
- Windows下进程和线程同步的四种控制方法
- Windows下进程和线程同步的四种控制方法
- Windows线程同步的方法
- Windows线程同步的方法
- Windows线程同步的方法
- windows线程同步的方法
- Windows线程同步的方法
- Windows终止线程的四种方法
- Windows终止线程的四种方法
- C++线程同步的四种方式(Windows)
- 10.笔记JAVA框架学习——Bean之间关系
- Android 中使用Javassist
- CKfinder和CKeditor使用笔记
- JAVA基础复习十五-Collection集合子类-List集合的子类
- STM8串口打印调试信息
- Windows线程同步的四种方法
- body标签的属性练习
- 垃圾回收器如何工作
- Robot Framework-Mac版本安装
- Linux内核:IO设备的抽象管理方式
- Qt之QSS使用
- 线程的创建方式
- Centos7无法上网
- Linux系统知识小结(十)