关于多线程之间的同步常用的三种方法

时间:2021-08-06 15:44:55

</pre>一个进程如果包含多个线程,并且这多个线程之间需要访问同一个对象是,就会涉及到多线程之间的同步,否者就会出现不可预料的错误。多线程之间同步可以采用互斥对象,事件对象,和关键代码段的方法。</p><p><span style="white-space:pre">	互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID和一个计数器。ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。</span></p><p><span style="white-space:pre">	事件对象也属于内核对象,包含一个使用计数,一个用于指明该事件是一个自动重置的事件还是一个人工重置的事件的布尔值,另一个用于指明该事件处于已通知状态还是未通知状态的布尔值。有两种不同类型的事件对象。一种是人工重置的事件,另一种是自动重置的事件。当人工重置的事件得到通知时,等待该事件的所有线程均变为可调度线程。当一个自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。</span></p><p><span style="white-space:pre">	关键代码段(临界区)工作在用户方式下。关键代码段(临界区)是指一个小代码段,在代码能够执行前,它必须独占对某些资源的访问权。</span></p><p><span style="white-space:pre">	</span>互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但利用互斥对象和事件对象这样的内核对象,可以在多个进程中的各个线程间进行同步。关键代码段是工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在等待进入关键代码段时无法设定超时值。</p><p><span style="white-space:pre">	</span>对应三种多线程间的同步方式,给出下面三个实例以供参考。</p><p>互斥对象:</p><p><pre name="code" class="cpp">#include <windows.h>
#include <iostream>


using namespace std ;


DWORD WINAPI Fun1Proc(
LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
);
int index=0;
int tickets=100;
long label1=0;
long label2=0;
DWORD dw1=0;
DWORD dw2=0;
HANDLE hMutex;//创建互斥对象,用于线程间的同步
void main()
{


//while(index++<1000)
//cout<<"main thread is running!"<<endl;

hMutex=CreateMutex(NULL,FALSE,"tickets");
if(hMutex)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only instance can run!"<<endl;
//getchar();
Sleep(100);
return;
}
}//这里一定注意要先建立好Mutex在创建线程,否者会出现奇怪的错误。


HANDLE hThread1;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
CloseHandle(hThread1);


HANDLE hThread2;
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread2);
Sleep(4000);
getchar();


}


DWORD WINAPI Fun1Proc(
LPVOID lpParameter
)
{
/*while(index++<1000)
cout<<"thread1 thread is running!"<<endl;*/

while(true)
{
dw1=WaitForSingleObject(hMutex,INFINITE);
if(dw1==WAIT_FAILED)
{
cout<<"wait1 failed!"<<endl;


}
//Sleep(1);
if(tickets>0)
cout<<"Thread1 sells ticket:"<<tickets--<<endl;
else
break;

label1=ReleaseMutex(hMutex);
if(label1==0)
{
cout<<"release1 failed!"<<endl;
}

}
return 0;
}


DWORD WINAPI Fun2Proc(
LPVOID lpParameter
)
{

while(true)
{
//Sleep(5);
dw2=WaitForSingleObject(hMutex,INFINITE);
if(dw2==WAIT_FAILED)
{
cout<<"wait2 failed!"<<endl;


}
//Sleep(1);
if(tickets>0)
cout<<"Thread2 sells ticket:"<<tickets--<<endl;
else
break;

label2=ReleaseMutex(hMutex);
if(label2==0)
{
cout<<"release2 failed!"<<endl;
}
}
return 0;
}


事件对象:

#include <windows.h>
#include <iostream>

using namespace std ;

DWORD WINAPI Fun1Proc(
LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
);


int tickets=100;
long label1=0;
long label2=0;
DWORD dw1=0;
DWORD dw2=0;
HANDLE g_hEvent;
void main()
{

g_hEvent=CreateEvent(NULL,FALSE,FALSE,"tickets");//创建事件对象,初始化状态为非信号状态的自动重置的事件对象
if(g_hEvent)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
cout<<"only instance can run!"<<endl;

getchar();
return;
}
}
SetEvent(g_hEvent);

HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);

Sleep(4000);
CloseHandle(g_hEvent);
getchar();

}

DWORD WINAPI Fun1Proc(
LPVOID lpParameter
)
{
/*while(index++<1000)
cout<<"thread1 thread is running!"<<endl;*/

while(true)
{
dw1=WaitForSingleObject(g_hEvent,INFINITE);
if(dw1==WAIT_FAILED)
{
cout<<"wait1 failed!"<<endl;

}
//Sleep(1);
if(tickets>0)
cout<<"Thread1 sells ticket:"<<tickets--<<endl;
else
break;

SetEvent(g_hEvent);

}
return 0;
}

DWORD WINAPI Fun2Proc(
LPVOID lpParameter
)
{

while(true)
{
//Sleep(5);
dw2=WaitForSingleObject(g_hEvent,INFINITE);
if(dw2==WAIT_FAILED)
{
cout<<"wait2 failed!"<<endl;

}
//Sleep(1);
if(tickets>0)
cout<<"Thread2 sells ticket:"<<tickets--<<endl;
else
break;

SetEvent(g_hEvent);
}
return 0;
}

关键代码段:

#include <windows.h>
#include <iostream>

using namespace std ;

DWORD WINAPI Fun1Proc(
LPVOID lpParameter
);
DWORD WINAPI Fun2Proc(
LPVOID lpParameter
);


int tickets=100;
CRITICAL_SECTION g_cs;
void main()
{

InitializeCriticalSection(&g_cs);


HANDLE hThread1;
HANDLE hThread2;
hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);

Sleep(4000);
getchar();
DeleteCriticalSection(&g_cs);
}

DWORD WINAPI Fun1Proc(
LPVOID lpParameter
)
{
/*while(index++<1000)
cout<<"thread1 thread is running!"<<endl;*/

while(true)
{
EnterCriticalSection(&g_cs);
//Sleep(10);
if(tickets>0)
{
//Sleep(100);
cout<<"Thread1 sells ticket:"<<tickets--<<endl;
}
else
break;

LeaveCriticalSection(&g_cs);
}
return 0;
}

DWORD WINAPI Fun2Proc(
LPVOID lpParameter
)
{

while(true)
{
EnterCriticalSection(&g_cs);
//Sleep(1);
if(tickets>0)
{
//Sleep(10);
cout<<"Thread2 sells ticket:"<<tickets--<<endl;
}
else
break;

LeaveCriticalSection(&g_cs);
}
return 0;
}