VC下线程同步的三种方法(互斥、事件、临界区)
2008-11-28 10:20
344 查看
首选使用临界区对象,主要原因是使用简单。
EnterCriticalSection()函数等候指定的危险区段对象的所有权。当调用的线程被允许所有权时,函数返回。
EnterCriticalSection (),一个单独进程的线程可以使用一个危险区段对象作为相互-排除同步。 进程负责分配被一个危险区段对象使用的内存, 它藉由声明一个CRITICAL_SECTION类型 的变量实现。在使用一个危险区段之前,进程的一些线程必须调用 InitializeCriticalSection 函数设定对象的初值.
为了要使互斥的访问被共享的资源,每个线程调用EnterCriticalSection 或者 TryEnterCriticalSection 功能,在执行访问被保护资源的任何代码段之前,请求危险区段的所有权。
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
InitializeCriticalSection(&g_csA);
InitializeCriticalSection(&g_csB);
Sleep(40000);
DeleteCriticalSection(&g_csA);
DeleteCriticalSection(&g_csB);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
EnterCriticalSection(&g_csA);
Sleep(1);
//EnterCriticalSection(&g_csB);//临界区的同步和互锁
if (tickets>0)
{
Sleep(1);
cout<<"Thread1 sell ticket :"<<tickets--<<endl;
//LeaveCriticalSection(&g_csB);
LeaveCriticalSection(&g_csA);
}
else
{
//LeaveCriticalSection(&g_csB);
LeaveCriticalSection(&g_csA);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
EnterCriticalSection(&g_csB);
Sleep(1);
EnterCriticalSection(&g_csA);
if (tickets>0)
{
Sleep(1);
cout<<"Thread2 sell ticket :"<<tickets--<<endl;
LeaveCriticalSection(&g_csA);
LeaveCriticalSection(&g_csB);
}
else
{
LeaveCriticalSection(&g_csA);
LeaveCriticalSection(&g_csB);
break;
}
}
return 0;
}
--------------------------------------------------------------------------------
二、使用互斥对象
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT
WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int index =0;
int tickets=100;
HANDLE hMutex;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//创建线程
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
//**************************************************************
//保证应用程序只有一个实例运行,创建一个命名的互斥对象.
hMutex=CreateMutex(NULL,TRUE,LPCTSTR("tickets"));
//创建时主线程拥有该互斥对象,互斥对象的线程ID为主线程的ID,同时将该互斥对象内部计数器置为1
if (hMutex)
{
if (ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
//Sleep(40000);
return;
}
}
//**************************************************************
WaitForSingleObject(hMutex,INFINITE);
//使用该函数请求互斥对象时,虽说该对象处于无信号状态,但因为请求的线程ID和该互斥对象所有者的线程ID是相同的.所以仍然可以请求到这个互斥对象,于是该互斥对象内部计数器加1,内部计数器的值为2. 意思是有两个等待动作
ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值递减1,操作系统不会将这个互斥对象变为已通知状态.
ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值为0,同时将该对象设置为已通知状态.
//对于互斥对象来说,谁拥有谁释放
Sleep(40000);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE);//等待互斥对象有信号
if (tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket :"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);//设置该互斥对象的线程ID为0,并且将该对象设置为有信号状态
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if (tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket :"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
}
return 0;
三、使用事件对象
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
BOOL bManualReset, // reset type
BOOL bInitialState, // initial state
LPCTSTR lpName // object name
);
该函数创建一个Event同步对象,并返回该对象的Handle
lpEventAttributes 一般为NULL
bManualReset 创建的Event是自动复位还是人工复位 ,如果true,人工复位,
一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复
为无信号. 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,
该Event就会自动复位,变成无信号.
bInitialState 初始状态,true,有信号,false无信号
lpName Event对象名
一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()
来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()
来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待
其变为有信号.
PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event
对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.
对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于
人工复位的Event对象,它释放所有等待的thread.
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//**************************************************
//创建一个命名的自动重置事件内核对象
g_hEvent=CreateEvent(NULL,FALSE,FALSE,LPCTSTR("tickets"));
if (g_hEvent)
{
if (ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
//**************************************************
SetEvent(g_hEvent);
//创建线程
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
Sleep(40000);
//关闭事件对象句柄
CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
//ResetEvent(g_hEvent);
if (tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket :"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
//ResetEvent(g_hEvent);
if (tickets>0)
{
cout<<"Thread2 sell ticket :"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200864/121416_2.html
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200864/121416.html
EnterCriticalSection()函数等候指定的危险区段对象的所有权。当调用的线程被允许所有权时,函数返回。
EnterCriticalSection (),一个单独进程的线程可以使用一个危险区段对象作为相互-排除同步。 进程负责分配被一个危险区段对象使用的内存, 它藉由声明一个CRITICAL_SECTION类型 的变量实现。在使用一个危险区段之前,进程的一些线程必须调用 InitializeCriticalSection 函数设定对象的初值.
为了要使互斥的访问被共享的资源,每个线程调用EnterCriticalSection 或者 TryEnterCriticalSection 功能,在执行访问被保护资源的任何代码段之前,请求危险区段的所有权。
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
InitializeCriticalSection(&g_csA);
InitializeCriticalSection(&g_csB);
Sleep(40000);
DeleteCriticalSection(&g_csA);
DeleteCriticalSection(&g_csB);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
EnterCriticalSection(&g_csA);
Sleep(1);
//EnterCriticalSection(&g_csB);//临界区的同步和互锁
if (tickets>0)
{
Sleep(1);
cout<<"Thread1 sell ticket :"<<tickets--<<endl;
//LeaveCriticalSection(&g_csB);
LeaveCriticalSection(&g_csA);
}
else
{
//LeaveCriticalSection(&g_csB);
LeaveCriticalSection(&g_csA);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
EnterCriticalSection(&g_csB);
Sleep(1);
EnterCriticalSection(&g_csA);
if (tickets>0)
{
Sleep(1);
cout<<"Thread2 sell ticket :"<<tickets--<<endl;
LeaveCriticalSection(&g_csA);
LeaveCriticalSection(&g_csB);
}
else
{
LeaveCriticalSection(&g_csA);
LeaveCriticalSection(&g_csB);
break;
}
}
return 0;
}
--------------------------------------------------------------------------------
二、使用互斥对象
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT
WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int index =0;
int tickets=100;
HANDLE hMutex;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//创建线程
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
//**************************************************************
//保证应用程序只有一个实例运行,创建一个命名的互斥对象.
hMutex=CreateMutex(NULL,TRUE,LPCTSTR("tickets"));
//创建时主线程拥有该互斥对象,互斥对象的线程ID为主线程的ID,同时将该互斥对象内部计数器置为1
if (hMutex)
{
if (ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
//Sleep(40000);
return;
}
}
//**************************************************************
WaitForSingleObject(hMutex,INFINITE);
//使用该函数请求互斥对象时,虽说该对象处于无信号状态,但因为请求的线程ID和该互斥对象所有者的线程ID是相同的.所以仍然可以请求到这个互斥对象,于是该互斥对象内部计数器加1,内部计数器的值为2. 意思是有两个等待动作
ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值递减1,操作系统不会将这个互斥对象变为已通知状态.
ReleaseMutex(hMutex);//释放一次互斥对象,该互斥对象内部计数器的值为0,同时将该对象设置为已通知状态.
//对于互斥对象来说,谁拥有谁释放
Sleep(40000);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE);//等待互斥对象有信号
if (tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket :"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);//设置该互斥对象的线程ID为0,并且将该对象设置为有信号状态
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex,INFINITE);
if (tickets>0)
{
Sleep(1);
cout<<"thread2 sell ticket :"<<tickets--<<endl;
}
else
break;
ReleaseMutex(hMutex);
}
return 0;
三、使用事件对象
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
BOOL bManualReset, // reset type
BOOL bInitialState, // initial state
LPCTSTR lpName // object name
);
该函数创建一个Event同步对象,并返回该对象的Handle
lpEventAttributes 一般为NULL
bManualReset 创建的Event是自动复位还是人工复位 ,如果true,人工复位,
一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复
为无信号. 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,
该Event就会自动复位,变成无信号.
bInitialState 初始状态,true,有信号,false无信号
lpName Event对象名
一个Event被创建以后,可以用OpenEvent()API来获得它的Handle,用CloseHandle()
来关闭它,用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()
来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待
其变为有信号.
PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event
对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.
对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于
人工复位的Event对象,它释放所有等待的thread.
#include <windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
HANDLE g_hEvent;
void main()
{
HANDLE hThread1;
HANDLE hThread2;
//**************************************************
//创建一个命名的自动重置事件内核对象
g_hEvent=CreateEvent(NULL,FALSE,FALSE,LPCTSTR("tickets"));
if (g_hEvent)
{
if (ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only one instance can run!"<<endl;
return;
}
}
//**************************************************
SetEvent(g_hEvent);
//创建线程
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
Sleep(40000);
//关闭事件对象句柄
CloseHandle(g_hEvent);
}
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
//ResetEvent(g_hEvent);
if (tickets>0)
{
Sleep(1);
cout<<"thread1 sell ticket :"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
while (TRUE)
{
WaitForSingleObject(g_hEvent,INFINITE);
//ResetEvent(g_hEvent);
if (tickets>0)
{
cout<<"Thread2 sell ticket :"<<tickets--<<endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return 0;
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200864/121416_2.html
文章出处:http://www.diybl.com/course/3_program/c++/cppsl/200864/121416.html
相关文章推荐
- VC下线程同步的三种方法(互斥、事件、临界区)
- VC下线程同步的三种方法(互斥、事件、临界区)
- VC下线程同步的三种方法(互斥、事件、临界区)
- VC下线程同步的三种方法(互斥、事件、临界区)
- VC下线程同步的三种方法(互斥、事件、临界区)/(转)
- VC下线程同步的三种方法(互斥、事件、临界区)
- 线程同步的三种方法(互斥,事件,临界区) 之一 使用临界区对象
- 线程同步的三种方法(互斥,事件,临界区) 之二 使用互斥对象
- 线程同步的三种方法(互斥,事件,临界区) 之三 使用事件对象
- VC下线程同步的三种方法(互斥、事件、临界区) - pl2597758的专栏 - CSDNBlog
- VC++中四种进程或线程同步互斥的控制方法
- VC++中四种进程或线程同步互斥的控制方法
- VC++中四种进程或线程同步互斥的控制方法
- 临界区、事件、互斥量、 信号量--四种控制多线程同步与互斥的方法
- *Delphi多线程编程--线程同步的方法(事件、互斥、信号、计时器)简介
- 线程同步与临界区对象、互斥对象、事件对象
- VC++中四种进程或线程同步互斥的控制方法
- VC++中四种进程或线程同步互斥的控制方法
- VC++中四种进程或线程同步互斥的控制方法
- VC++中四种进程或线程同步互斥的控制方法