前面的关于线程同步的两种方法都有讲解:
前面的一个帖子说了如何实现线程的同步,利用的是信号量来实现,关键的函数是:CreateMutex和ReleaseMutex函数。
下面,看看事件方式如何实现同步吧!
代码:
从代码上可以看到,除了对应的函数不同以外,其他的方式都是相同的,即:
对应的函数从CreateMutex变成了CreateEvent,而释放资源则由ReleaseMutex变为SetEvent了。
效果相同,输出都是:
对于两个线程函数,注意原型都要一致,也就是DWORD WINAPI XXX(LPVOID );所以需要编写两个线程函数,也就是CreateThread函数来实现。
其次,就需要实现两个线程之间的协调,如何协调呢?
WaitForSingleObject,里面的参数设定了信号量的占用者,也就阻塞了其他的线程执行,待它执行完毕后,ReleaseMutex函数则释放了该信号量,实现了其他线程的运行。
总体上来说,这个程序比较简单。
但是,基本的函数和API,都是很基本的线程操作,需要注意。。。
下面讲解第三种方法:基于临界区的方法:
代码:
前面的一个帖子说了如何实现线程的同步,利用的是信号量来实现,关键的函数是:CreateMutex和ReleaseMutex函数。
下面,看看事件方式如何实现同步吧!
代码:
#include
<
windows.h
>
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID Param);
int time;
HANDLE events;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
events = CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent(events);
Sleep(4000);
CloseHandle(events);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1){
WaitForSingleObject(events,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程1运行第" << time++ << "次" << endl;
}
else
break;
SetEvent(events);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1){
WaitForSingleObject(events,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程2运行第" << time++ << "次" << endl;
}
else
break;
SetEvent(events);
}
return 0;
}
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID Param);
int time;
HANDLE events;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
events = CreateEvent(NULL,FALSE,FALSE,NULL);
SetEvent(events);
Sleep(4000);
CloseHandle(events);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1){
WaitForSingleObject(events,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程1运行第" << time++ << "次" << endl;
}
else
break;
SetEvent(events);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1){
WaitForSingleObject(events,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程2运行第" << time++ << "次" << endl;
}
else
break;
SetEvent(events);
}
return 0;
}
从代码上可以看到,除了对应的函数不同以外,其他的方式都是相同的,即:
对应的函数从CreateMutex变成了CreateEvent,而释放资源则由ReleaseMutex变为SetEvent了。
效果相同,输出都是:
线程1运行第0次
线程2运行第1次
线程1运行第2次
线程2运行第3次
线程1运行第4次
线程2运行第5次
线程1运行第6次
线程2运行第7次
线程1运行第8次
线程2运行第9次
线程1运行第10次
线程2运行第11次
线程1运行第12次
线程2运行第13次
线程1运行第14次
线程2运行第15次
线程1运行第16次
线程2运行第17次
线程1运行第18次
线程2运行第19次
线程1运行第20次
Press any key to continue
线程2运行第1次
线程1运行第2次
线程2运行第3次
线程1运行第4次
线程2运行第5次
线程1运行第6次
线程2运行第7次
线程1运行第8次
线程2运行第9次
线程1运行第10次
线程2运行第11次
线程1运行第12次
线程2运行第13次
线程1运行第14次
线程2运行第15次
线程1运行第16次
线程2运行第17次
线程1运行第18次
线程2运行第19次
线程1运行第20次
Press any key to continue
#include
<
windows.h
>
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
HANDLE Mutex;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
Mutex = CreateMutex(NULL,FALSE,NULL);
cout << "运行主线程!" << endl;
Sleep(4000);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1){
WaitForSingleObject(Mutex,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程1运行第" << time++ << "次" << endl;
}
else
break;
ReleaseMutex(Mutex);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1){
WaitForSingleObject(Mutex,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程2运行第" << time++ << "次" << endl;
}
else
break;
ReleaseMutex(Mutex);
}
return 0;
}
首先插入上面的一段代码,说明下功能,就是使得每次每一个线程输出一个数据。通过信号量来使得线程之间不会发生冲突。
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
HANDLE Mutex;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
Mutex = CreateMutex(NULL,FALSE,NULL);
cout << "运行主线程!" << endl;
Sleep(4000);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1){
WaitForSingleObject(Mutex,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程1运行第" << time++ << "次" << endl;
}
else
break;
ReleaseMutex(Mutex);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1){
WaitForSingleObject(Mutex,INFINITE);
if(time <= 20){
Sleep(1);
cout << "线程2运行第" << time++ << "次" << endl;
}
else
break;
ReleaseMutex(Mutex);
}
return 0;
}
对于两个线程函数,注意原型都要一致,也就是DWORD WINAPI XXX(LPVOID );所以需要编写两个线程函数,也就是CreateThread函数来实现。
其次,就需要实现两个线程之间的协调,如何协调呢?
WaitForSingleObject,里面的参数设定了信号量的占用者,也就阻塞了其他的线程执行,待它执行完毕后,ReleaseMutex函数则释放了该信号量,实现了其他线程的运行。
总体上来说,这个程序比较简单。
但是,基本的函数和API,都是很基本的线程操作,需要注意。。。
下面讲解第三种方法:基于临界区的方法:
代码:
#include
<
windows.h
>
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
CRITICAL_SECTION critical;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
InitializeCriticalSection(&critical);
Sleep(4000);
DeleteCriticalSection(&critical);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1)
{
EnterCriticalSection(&critical);
if(time <= 20)
{
Sleep(1);
cout << "子线程1第" << time ++ << "次"<< endl;
}
else
break;
LeaveCriticalSection(&critical);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1)
{
EnterCriticalSection(&critical);
if(time <= 20)
{
Sleep(1);
cout << "子线程2第" << time ++ << "次" << endl;
}
else
break;
LeaveCriticalSection(&critical);
}
return 0;
}
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
CRITICAL_SECTION critical;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
InitializeCriticalSection(&critical);
Sleep(4000);
DeleteCriticalSection(&critical);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1)
{
EnterCriticalSection(&critical);
if(time <= 20)
{
Sleep(1);
cout << "子线程1第" << time ++ << "次"<< endl;
}
else
break;
LeaveCriticalSection(&critical);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1)
{
EnterCriticalSection(&critical);
if(time <= 20)
{
Sleep(1);
cout << "子线程2第" << time ++ << "次" << endl;
}
else
break;
LeaveCriticalSection(&critical);
}
return 0;
}
实际上,这三种方法的实现都相同,只不过,所使用的函数不同而已,这里对于临界区的函数,就是对应的:
InitializeCriticalSection, DeleteCriticalSection, EnterCriticalSection, LeaveCriticalSection函数而已。
说说三者的区别吧:
基于互斥对象和事件对象的线程同步,属于内核对象,速度比较慢,不过可以在多个进程中的各个线程之间同步。
基于离你家而且的线程同步,属于用户方式下的,速度比较快,但是容易进入死锁状态!
这三种方法,都是可以实现Windows下面的线程同步,使得各个线程之间可以互通消息,实现交互式的访问。特别是对于共享资源的情况,必须要使用线程同步,否则会发生与时间有关的错误,前面的帖子中,列举出来的关于乱码和竞争的现象,输出信息的杂乱,都是说明了这一点。
在线程发生竞争的时候,也需要使用线程同步,否则,一旦发生与时间有关的错误,就会产生难以预料的BUG。对于实际编程的意义尤其重大!
在做完上面的这三种方法后,余下的就是基于信号量的,函数也不同,不再多说,如下:
#include
<
windows.h
>
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
HANDLE sema;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
sema = CreateSemaphore(NULL,1,1,NULL);
Sleep(4000);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1)
{
WaitForSingleObject(sema,INFINITE);
if(time <= 20)
{
Sleep(1);
cout << "子线程1第" << time ++ << "次"<< endl;
}
else
break;
ReleaseSemaphore(sema,1,NULL);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1)
{
WaitForSingleObject(sema,INFINITE);
if(time <= 20)
{
Sleep(1);
cout << "子线程2第" << time ++ << "次" << endl;
}
else
break;
ReleaseSemaphore(sema,1,NULL);
}
return 0;
}
#include < iostream >
using namespace std;
DWORD WINAPI Fun1Proc(LPVOID param);
DWORD WINAPI Fun2Proc(LPVOID param);
int time = 0 ;
HANDLE sema;
void main()
{
HANDLE thread1,thread2;
thread1 = CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
thread2 = CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(thread1);
CloseHandle(thread2);
sema = CreateSemaphore(NULL,1,1,NULL);
Sleep(4000);
}
DWORD WINAPI Fun1Proc(LPVOID param)
{
while(1)
{
WaitForSingleObject(sema,INFINITE);
if(time <= 20)
{
Sleep(1);
cout << "子线程1第" << time ++ << "次"<< endl;
}
else
break;
ReleaseSemaphore(sema,1,NULL);
}
return 0;
}
DWORD WINAPI Fun2Proc(LPVOID param)
{
while(1)
{
WaitForSingleObject(sema,INFINITE);
if(time <= 20)
{
Sleep(1);
cout << "子线程2第" << time ++ << "次" << endl;
}
else
break;
ReleaseSemaphore(sema,1,NULL);
}
return 0;
}