线程间实现同步互斥的方法.docx
《线程间实现同步互斥的方法.docx》由会员分享,可在线阅读,更多相关《线程间实现同步互斥的方法.docx(13页珍藏版)》请在冰豆网上搜索。
线程间实现同步互斥的方法
最近关注了几个其他线程间同步的方法,之前用的比较简单了,使用全局变量置标志,在线程中根据标志实现相应操作,搜索了一下,还有些其他方法,自己做了Demo,在此总结一下:
1.临界区(CriticalSection):
适合一个进程内的多线程访问公共区域或代码段时使用。
API:
VOID EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); //进入临界区
VOID LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection); //离开临界区
某一线程调用EnterCriticalSection函数进入临界区后,必须保证最后可以调用LeaveCriticalSection,否则公共区域无法释放,并被其它线程访问。
在MFC中封装了CCriticalSection类,该类提供进入临界区和离开临界区的函数Lock()和Unlock()
Ex:
CCriticalSection cs; //临界区对象
void ThreadFunction()
{
cs.Lock();
//代码
cs.Unlock();
}//endThreadFunction
2.互斥量(Mutex):
适合不同进程内多线程访问公共区域或代码段时使用,与临界区相似。
HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,BOOLbInitialOwner,LPCTSTRlpName);
//创建一个互斥量,返回值为这个互斥量的句柄。
参数bInitialOwner表示是否由调用此函数的进程拥有此互斥量
API:
HANDLEOpenMutex(DWORDdwDesiredAccess,BOOLhInheritHandle,LPCTSTRlpName);//打开一个已创建的互斥量
BOOLReleaseMutex(HANDLEhMutex); //释放
MFC中封装了CMutex类,同样的函数Lock()和Unlock()
3.事件(Event):
通过线程间触发事件实现同步互斥
API:
HANDLECreateEvent(LPSECURITY_ATTRIBUTESlpEventAttributes,BOOLbManualReset,BOOLbInitialState,LPCTSTRlpName); //创建一个事件,返回值为事件句柄参数bManualReset表示是否通过手动重设事件,参数为TRUE,则需要调用ResetEvent重设事件,否则为自动重设
HANDLEOpenEvent(DWORDdwDesizedAccess,BOOLbInheritHandle,LPCTSTRlpName);//打开事件
在MFC中封装了CEvent类,包括SetEvent()触发事件、PulseEvent暂停事件、ResetEvent()重设事件及Unlock()释放事件句柄
4.信号量(Semaphore):
与临界区和互斥量不同,可以实现多个线程同时访问公共区域数据,原理与操作系统中PV操作类似,先设置一个访问公共区域的线程最大连接数,每有一个线程访问共享区资源数就减一,直到资源数小于等于零。
API:
HANDLECreateSemaphore(LPSECURITY_ATTRIBUTES,LONGlInitialCount,LONGlMaxmemCount,LPCTSTRlpName);
//创建信号量,返回句柄,参数lInitialCount为信号量资源初始数基数,参数lMaxmemCount为该信号量的最大数
HANDLEOpenSemaphore(DWORDdwDesiredAccess,BOOLhInheriHandle,LPCTSTRlpName);//打开信号量
BOOLReleaseSemaphore(HANDLEbSemaphore,LONGlReleaseCount,LPLONGlpPreviousCount);//释放信号量
在MFC中封装了CSemaphore类,声明该类的对象后使用API:
WaitForSingleObject()函数实现等待访问资源,使用ReleaseSemaphore函数释放资源,函数参数中需串入信号量对象句柄。
总结:
上述4个实现线程同步互斥的类均派生自虚基类CSyncObject,除临界区外其它3中方式均可用于多进程间线程同步互斥。
另:
线程触发自定义事件
可使用API函数PostThreadMessage()函数,或创建CWinThread对象,调用该类的PostThreadMessage()
互斥锁是一种通过简单的加锁的方法来控制对共享资源的存取,用于解决线程间资源访问的唯一性问题。
互斥锁有上锁和解锁两种状态,在同一时刻只能有一个线程掌握某个互斥的锁,拥有上锁状态的线程可以对共享资源进行操作。
若其他线程希望对一个已经上了锁的互斥锁上锁,则该线程会被挂起,直到上锁的线程释放掉互斥锁为止。
操作互斥锁的基本函数有:
1.pthread_mutex_init ——互斥锁初始化;2.pthread_mutex_lock——互斥锁上锁(阻塞版);3.pthread_mutex_trtylock——互斥锁上锁(非阻塞版);4.pthread_mutex_unlock——互斥锁解锁;5.pthread_mutex_destory——消除互斥锁。
线程互斥锁的数据类型是pthread_mutex_t,在使用前,要对其进行初始化,有以下两种方法:
静态初始化:
可以把常量PTHREAD_MUTEX_INITIALIZER赋给静态分配的互斥锁变量;
动态初始化:
在申请内存之后,通过pthread_mutex_init进行初始化,在释放内存前需要调用pthread_mutex_destroy。
互斥锁的一个明显缺点是它只有两种状态:
锁定和非锁定。
而条件变量通过允许线程阻塞和等待另一个线程放松信号的方法弥补了互斥锁的不足,它常和互斥锁一块使用。
使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。
一旦其他的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正在被此条件阻塞的线程。
这些线程将重新锁定互斥锁并重新测试条件是否满足。
条件变量上的基本操作有两个。
1.触发条件:
当条件变为true时;2.等待条件:
挂起线程直到其他线程触发条件。
条件变量的数据类型是pthreead_cond_t,在使用前也需要初始化
一、什么是互斥锁
另一种在多线程程序中同步访问手段是使用互斥量。
程序员给某个对象加上一把“锁”,每次只允许一个线程去访问它。
如果想对代码关键部分的访问进行控制,你必须在进入这段代码之前锁定一把互斥量,在完成操作之后再打开它。
互斥量函数有
pthread_mutex_init初始化一个互斥量
pthread_mutex_lock给一个互斥量加锁
pthread_mutex_trylock加锁,如果失败不阻塞
pthread_mutex_unlock解锁
可以通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据。
互斥量从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。
对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。
如果释放互斥锁时有多个线程阻塞,所以在该互斥锁上的阻塞线程都会变成可进行状态,第一个变成运行状态的线程可以对互斥量加锁,其他线程在次被阻塞,等待下次运行状态。
互斥量用pthread_mutex_t数据类型来表示,在使用互斥量以前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以通过调用pthread_mutex_init函数进行初始化,如果动态地分配互斥量,那么释放内存前需要调用pthread_mutex_destroy.
二、初始化/回收互斥锁
1.
名称:
:
pthread_mutexattr_init
功能:
初始化互斥锁。
头文件:
#include
函数原形:
intpthread_mutex_init(pthread_mutex_t*mutex,
constpthread_mutex_t*attr);
参数:
mutex 互斥量
attr 互斥锁属性
返回值:
若成功则返回0,否则返回错误编号。
mutex是我们要锁住的互斥量,attr是互斥锁的属性,可用相应的函数修改,我们在下章介绍,要用默认的属性初始化互斥量,只需把attr设置为NULL。
对互斥量进行加锁,需要调用pthread_mutex_lock,如果互斥量已经上锁,调用线程阻塞直至互斥量解锁。
对互斥量解锁,需要调用pthread_mutex_unlock.
如果线程不希望被阻塞,他可以使用pthread_mutex_trylock尝试对互斥量进行加锁。
如果调用pthread_mutex_trylock时互斥量处于未锁住状态,那么pthread_mutex_trylock将锁住互斥量,否则就会失败,不能锁住互斥量,而返回EBUSY。
下面试例子可以证明对互斥量加锁的必要性:
我们先来看不加锁的程序。
#inlcude
#include
#inlcude
#include
viid*thread_function(void*arg);
intrun_now=1; /*用run_now代表共享资源*/
intmain()
{
intprint_count1=0;/*用于控制循环*/
prhread_ta_thread;
if(pthread_create(&a_thread,NULL,thread_function,NULL)!
=0) /*创建一个进程*/
{
perror(“Threadcreateionfailed”);
exit
(1);
}
while(print_count1++<5)
{
if(run_now==1) /主线程:
如果run_now为1就把它修改为2*/
{
printf(“mainthreadisrun\n”);
run_now=2;
}
else
{
printf(“mainthreadissleep\n”);
sleep
(1);
}
}
pthread_join(a_thread,NULL);/*等待子线程结束*/
exit(0);
}
void*thread_function(void*arg)
{
intprint_count2=0;
while(print_count2++<5)
{
if(run_now==2) /子线程:
如果run_now为1就把它修改为1*/
{
printf(“functionthreadisrun\n”);
run_now=1;
}
else
{
printf(“functionthreadissleep\n”);
sleep
(1);
}
}
pthread_exit(NULL);
}
运行上面程序的运行结果为:
functionthreadissleep
mainthreadisrun
mainthreadissleep
mainthreadissleep
functionthreadisrun
functionthreadissleep
mainthreadisrun
mainthreadissleep
functionthreadisrun
functionthreadissleep
我们可以看到main线程和function线程是交替运行的。
它们都可以对run_now进行操作。
下面是加锁的程序。
#inlcude
#include
#inlcude
viid*thread_function(void*arg);
intrun_now=1; /*用run_now代表共享资源*/
pthread_mutex_twork_mutex; /*定义互斥量*/
intmain()
{
intres;
intprint_count1=0;
prhread_ta_thread;
if(pthread_mutex_init(&work_mutex,NULL)!
=0) /*初始化互斥量*/
{
perror(“Mutexinitfaied”);
exit
(1);
}
if(pthread_create(&a_thread,NULL,thread_function,NULL)!
=0) /*创建新线程*/
{
perror(“Threadcreateionfailed”);
exit
(1);
}
if(pthread_mutex_lock(&work_mutex)!
=0) /*对互斥量加锁*/
{
preeor(“Lockfailed”);
exit
(1);
}
else
printf(“mainlock\n”);
while(print_count1++<5)
{
if(run_now==1) /主线程:
如果run_now为1就把它修改为2*/
{
printf(“mainthreadisrun\n”);
run_now=2;
}
else
{
printf(“mainthreadissleep\n”);
sleep
(1);
}
}
if(pthread_mutex_unlock(&work_mutex)!
=0)/*对互斥量解锁*/
{
preeor(“unlockfailed”);
exit
(1);
}
else
printf(“mainunlock\n”);
pthread_mutex_destroy(&work_mutex);/*收回互斥量资源*/
pthread_join(a_thread,NULL);/*等待子线程结束*/
exit(0);
}
void*thread_function(void*arg)
{
intprint_count2=0;
sleep
(1);
if(pthread_mutex_lock(&work_mutex)!
=0)
{
perror(“Lockfailed”);
exit
(1);
}
else
printf(“functionlock\n”);
while(print_count2++<5)
{
if(run_now==2) /分进程:
如果run_now为1就把它修改为1*/
{
printf(“functionthreadisrun\n”);
run_now=1;
}
else
{
printf(“functionthreadissleep\n”);
sleep
(1);
}
}
if(pthread_mutex_unlock(&work_mutex)!
=0) /*对互斥量解锁*/
{
perror(“unlockfailed”);
exit
(1);
}
else
printf(“functionunlock\n”);
pthread_exit(NULL);
}
下面是运行结果:
mainlock
mainthreadisrun
mainthreadissleep
mainthreadissleep
mainthreadissleep
mainthreadissleep
mainunlock
functionlock
functionthreadisrun
functionthreadissleep
functionthreadissleep
functionthreadissleep
functionthreadissleep
functionunlock
我们从运行结果可以看到,当主进程把互斥量锁住后,子进程就不能对共享资源进行操作了