刚开始接触线程同步问题,在工程中遇到了这些问题,之前其实根本没理解,现在才刚刚理解。
要掌握这些问题,首先要了解线程同步和互斥的区别,最简单的区别方式是,同步是线程之间有顺序问题,一个线程必须等待另一个线程执行完某些任务后才能开始执行,而互斥则只是对资源的互斥访问,但是谁先谁后没有区别。
关键段CRITICAL_SECTION,互斥量Mutex只能实现资源互斥,不能实现线程同步问题,如果线程之间有同步的关系,则需要使用Event和Semahore来实现,而后两者也可以实现互斥,同时解决同步。Event是相对简单,且使用较多,现在使用关键段和事件解决以下问题:
主线程启动10个子线程并将表示子线程序号的变量地址作为参数传递给子线程。子线程接收参数 -> sleep(50) -> 全局变量++ -> sleep(0) -> 输出参数和全局变量。
该问题是在http://blog.csdn.net/morewindows/article/details/7442333中看到的问题,讲解也挺好,我自己实现了一下:
#include <iostream>
#include <Windows.h>
using namespace std;
const int THREADNUM = 10;
HANDLE threadHandles[THREADNUM];
int count = 0;
CRITICAL_SECTION cs; //控制count互斥访问
HANDLE hEvent; //用事件控制传递的参数i的同步,主线程与子线程的同步
DWORD WINAPI threadProc(LPVOID lpParam);
int main()
{
//初始化关键段区域
InitializeCriticalSection(&cs);
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (hEvent == NULL)
{
cout << "创建事件对象错误" << endl;
CloseHandle(hEvent);
}
for (int i = 0; i < THREADNUM; i++)
{
threadHandles[i] = CreateThread(NULL, 0, threadProc, (LPVOID)i, 0, NULL);
if (threadHandles[i] == NULL) //创建失败返回值是NULL
{
cout << "线程创建错误!" << endl;
}
WaitForSingleObject(hEvent, INFINITE); //等待子线程参数传递和打印完成在执行下一个循环
}
WaitForMultipleObjects(THREADNUM, threadHandles, TRUE, INFINITE);
for (int i = 0; i < THREADNUM; i++)
{
CloseHandle(threadHandles[i]);
}
CloseHandle(hEvent);
system("pause");
return 0;
}
DWORD WINAPI threadProc(LPVOID lpParam)
{
int id = (int)lpParam;
Sleep(50);
EnterCriticalSection(&cs);
count++;
Sleep(0);
cout << "线程序号:" << id << " count值为:" << count << endl;
SetEvent(hEvent); //子线程使用完参数后,设置事件为通知状态,主线程可以执行++操作
LeaveCriticalSection(&cs);
return 0;
}
运行结果如下“
以上看出,线程的序号正序输出,count值也按顺序打印。
总结:关键段实现了全局变量count的互斥使用,event实现了主线程与子线程参数传递和打印之间的同步
以下是信号量实现方式:
#include <iostream>
#include <Windows.h>
using namespace std;
const int THREADNUM = 10;
HANDLE threadHandles[THREADNUM];
int count = 0;
CRITICAL_SECTION cs; //控制count互斥访问
HANDLE hSemaphore; //用信号量实现主线程与子线程的同步
DWORD WINAPI threadProc(LPVOID lpParam);
int main()
{
//初始化关键段区域
InitializeCriticalSection(&cs);
hSemaphore = CreateSemaphore(NULL, 0, 1, NULL);
if (hSemaphore == NULL)
{
cout << "创建事件对象错误" << endl;
CloseHandle(hSemaphore);
}
for (int i = 0; i < THREADNUM; i++)
{
threadHandles[i] = CreateThread(NULL, 0, threadProc, (LPVOID)i, 0, NULL);
if (threadHandles[i] == NULL) //创建失败返回值是NULL
{
cout << "线程创建错误!" << endl;
}
WaitForSingleObject(hSemaphore, INFINITE); //等待可用信号量,先挂起,等待线程运行完
}
WaitForMultipleObjects(THREADNUM, threadHandles, TRUE, INFINITE);
for (int i = 0; i < THREADNUM; i++)
{
CloseHandle(threadHandles[i]);
}
CloseHandle(hSemaphore);
system("pause");
return 0;
}
DWORD WINAPI threadProc(LPVOID lpParam)
{
int id = (int)lpParam;
Sleep(50);
EnterCriticalSection(&cs);
count++;
Sleep(0);
cout << "线程序号:" << id << " count值为:" << count << endl;
LeaveCriticalSection(&cs);
ReleaseSemaphore(hSemaphore, 1, NULL); //子线程使用完参数后,释放信号量,
return 0;
}