博客
关于我
vc++多线程编程
阅读量:796 次
发布时间:2023-02-26

本文共 3855 字,大约阅读时间需要 12 分钟。

多线程编程中的同步机制比较

在多线程编程中,确保不同线程能够协调工作是开发者需要解决的重要问题。为了避免数据竞态和死锁等问题,C++ 提供了几种常用的同步机制。本文将从事件、临界区、信号量到互斥对象等多种方式进行详细分析,帮助开发者更好地理解和选择合适的同步机制。

事件对象

事件对象是多线程编程中常用的同步机制之一。通过定义事件标志和等待事件的方式,开发者可以实现线程之间的通信和协调。在 C++ 中,事件对象可以通过 CreateEventSetEvent 等函数来创建和操作。

#include 
int iGolbalCount = 0;
int iMax = 12;
HANDLE hEvent;
int main() {
hEvent = CreateEvent(NULL, FALSE, FALSE, "iGolbalCount");
if (!hEvent) {
printf("创建事件对象失败!\n");
return 0;
}
SetEvent(hEvent);
Sleep(1000); // 等待事件被设置
// 创建线程并启动
HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
Sleep(40000); // 等待线程完成
CloseHandle(hEvent);
printf("主线程结束!\n");
return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam) {
while (TRUE) {
WaitForSingleObject(hEvent, INFINITE);
if (iGolbalCount < iMax) {
printf("这里是线程1,iGolbalCount=%d\n", iGolbalCount++);
SetEvent(hEvent);
} else {
SetEvent(hEvent);
break;
}
Sleep(10);
}
return 0;
}

临界区

临界区是一种轻量级的同步机制,通过占用共享资源的方式来确保线程只能在一个线程执行。临界区的使用需要显式地使用 EnterCriticalSectionLeaveCriticalSection 函数。

#include 
CRITICAL_SECTION cs;
int main() {
InitializeCriticalSection(&cs);
Sleep(50000); // 等待线程启动
// 创建线程并启动
HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
Sleep(50000); // 等待线程完成
DeleteCriticalSection(&cs);
printf("主线程结束!\n");
return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam) {
while (TRUE) {
EnterCriticalSection(&cs);
if (iGolbalCount < iMax) {
printf("这里是线程1,iGolbalCount=%d\n", iGolbalCount++);
} else {
break;
}
Sleep(10);
LeaveCriticalSection(&cs);
}
return 0;
}

信号量

信号量是一种更灵活的同步机制,通过等待和释放信号的方式来控制线程的执行。信号量可以支持多个等待对象,适用于需要动态控制线程数量的场景。

#include 
HANDLE hSemaphore;
int cMax = 1;
int main() {
hSemaphore = CreateSemaphore(NULL, cMax, cMax, NULL);
if (!hSemaphore) {
printf("创建信号量对象失败\n");
return 0;
}
Sleep(5000); // 等待线程启动
// 创建线程并启动
HANDLE hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
Sleep(5000); // 等待线程完成
printf("主线程结束!\n");
return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam) {
while (TRUE) {
DWORD dwWaitResult = WaitForSingleObject(hSemaphore, 0L);
if (dwWaitResult == WAIT_OBJECT_0) {
if (iGolbalCount < iMax) {
printf("这里是线程1,iGolbalCount=%d\n", iGolbalCount++);
ReleaseSemaphore(hSemaphore, 1, NULL);
} else {
ReleaseSemaphore(hSemaphore, 1, NULL);
break;
}
}
Sleep(10);
}
return 0;
}

互斥对象

互斥对象是一种更高级的同步机制,通过占用内存区间的方式来确保线程只能在一个线程执行。它比临界区更安全,且支持递归使用。

#include 
HANDLE hMutex;
int main() {
hMutex = CreateMutex(NULL, TRUE, "iGolbalCount");
if (!hMutex) {
printf("创建互斥对象失败!\n");
return 0;
}
Sleep(1000); // 等待线程启动
// 等待互斥对象并释放
WaitForSingleObject(hMutex, INFINITE);
ReleaseMutex(hMutex);
ReleaseMutex(hMutex); // 释放互斥对象
Sleep(5000); // 等待线程完成
printf("主线程结束!\n");
return 0;
}
DWORD WINAPI ThreadProc1(LPVOID lpParam) {
while (TRUE) {
WaitForSingleObject(hMutex, INFINITE);
if (iGolbalCount < iMax) {
printf("这里是线程1,iGolbalCount=%d\n", iGolbalCount++);
} else {
break;
}
Sleep(10);
ReleaseMutex(hMutex);
}
return 0;
}

总结

在多线程编程中,选择合适的同步机制对于确保线程安全至关重要。无论是事件对象、临界区、信号量还是互斥对象,每种机制都有其适用的场景。开发者需要根据具体需求选择最合适的方式,同时注意正确使用和释放资源,以避免潜在的竞态条件和内存泄漏问题。

转载地址:http://epvfk.baihongyu.com/

你可能感兴趣的文章
Openstack的视频学习
查看>>
openstack虚拟机迁移live-migration中libvirt配置
查看>>
ORACEL学习--理解over()函数
查看>>
oracle 10g的安装配置
查看>>
Oracle 11g 使用RMAN备份数据库
查看>>
Oracle 11g数据库安装和卸载教程
查看>>
ORACLE Bug 4431215 引发的血案—原因分析篇
查看>>
oracle dblink 创建使用 垮库转移数据
查看>>
oracle dblink结合同义词的用法 PLS-00352:无法访问另一数据库
查看>>
Oracle dbms_job.submit参数错误导致问题(ora-12011 无法执行1作业)
查看>>
oracle dg switchover,DG Switchover fails
查看>>
Oracle EBS-SQL (BOM-15):检查多层BOM(含common BOM).sql
查看>>
Oracle EBS环境下查找数据源(OAF篇)
查看>>
Oracle GoldenGate Director安装和配置(无图)
查看>>
oracle scott趣事
查看>>
oracle script
查看>>
Oracle select表要带双引号的原因
查看>>
Oracle SOA Suit Adapter
查看>>
Oracle Spatial空间数据库建立
查看>>
UML— 活动图
查看>>