线程教程.docx
- 文档编号:717808
- 上传时间:2023-04-29
- 格式:DOCX
- 页数:26
- 大小:23.37KB
线程教程.docx
《线程教程.docx》由会员分享,可在线阅读,更多相关《线程教程.docx(26页珍藏版)》请在冰点文库上搜索。
线程教程
创建一个C++线程类:
C++中独立于平台的线程
简介
最近,有人问到,是否有一种简单的方法创建一个C++类,以便有助于编写面向对象的线程,而且这个线程类还要有以下属性:
支持事件驱动及基于间隔的异步线程。
支持生成同种及特定的线程。
提供一个FCFS(先来先服务)的堆栈队列用于发送及处理多任务。
可移植。
易于实现。
为支持新类CThread,还需要编写出其他相关的类,这些类包括:
CMutexClass、CEventClass、CTask,CMutexClass及CEventClass提供资源管理,而CTask是一个用于派生的基类,其支持同种异步线程。
什么是线程?
每个进程至少有一个控制线程,且每个进程在同一时间至少能执行一项任务,有多种控制线程的进程称为多线程进程,一个多线程进程可在自身环境内异步运行多个任务。
资源管理——线程同步
因为进程内的线程分享相同的资源,所以需要在系统级别上设置控制机制来保证数据的完整性。
当一个线程修改了某个变量,而另一个线程试图读取它时,或者两个线程同时修改同一变量,就会影响到数据的完整性,为防止这个问题,操作系统提供了一种相互排斥对象,简写为mutex。
在多线程程序中,mutex是通过编程来实现的,可防止多个线程在同一时间访问同一资源。
当一个线程需要访问某一资源时,它必须先请求一个mutex,一旦线程得到一个mutex,其他想获取同一mutex的线程被阻塞,并处于低CPU占用的等待状态;一旦这个线程完成了数据访问,它会释放对应的mutex,这就允许其他线程获取以访问相关的数据。
如果mutex实现得不好,将会导致资源饥饿,也就是常说的死锁。
资源饥饿发生在当一个或多个线程竞争同一资源时,如果一个线程请求一个mutex两次,也可能会发生死锁。
--@page{margin:
2cm}TDP{margin-bottom:
0cm}P{margin-bottom:
0.21cm}-->
线程A
线程B
请求mutex1修改数据项1
请求mutex2修改数据项2
想要mutex2查看数据项2
想要mutex1查看数据项1
在上表中,就会发生死锁,因为线程A想要获取mutex2时被阻塞,而它正被线程B所持有;线程B想要获取mutex1时被阻塞,而它正被线程A所持有。
与mutex类似,Unix中的条件变量,也是一种同步机制。
条件变量允许线程会合,可让一个线程在有变化时通知另一个线程,这在Windows中,被称为events。
操作系统的调用
下表列出的函数均可用于在CMutexClass、CEventClass、CTask及CThread类中实现线程。
--@page{margin:
2cm}P{margin-bottom:
0.21cm}-->
函数
操作系统
描述
使用的类
CreateThread
Windows
创建一个Windows线程
CThread
pthread_create
UNIX-POSIXTHREADS
创建一个UNIX线程
CThread
pthread_join
UNIX-POSIXTHREADS
等待一个UNIX线程结束
CThread
pthread_attr_init
UNIX-POSIXTHREADS
将某一线程属性结构设为默认
CThread
pthread_attr_setstacksize
UNIX-POSIXTHREADS
设置线程属性结构的堆栈大小
CThread
WaitForSingleObject
Windows
等待一个对象有信号
CThread,CMutexClass,CEventClass
CreateMutex
Windows
创建一个命名或未命名的mutex
CMutexClass
CloseHandle
Windows
关闭某一Windows句柄以释放资源
CMutexClass,CEventClass,CThread
ReleaseMutex
Windows
释放某一之前获取,并由WaitForSingleObject锁定的 mutex
CMutexClass,CEventClass
pthread_mutexattr_init
UNIX-POSIXTHREADS
初始化某一mutex属性结构
CMutexClass,CEventClass
pthread_mutex_init
UNIX-POSIXTHREADS
用给定的属性结构初始化某一mutex
CMutexClass,CEventClass
pthread_mutex_lock
UNIX-POSIXTHREADS
锁定某一mutex
CMutexClass,CEventClass
pthread_mutex_unlock
UNIX-POSIXTHREADS
解锁某一之前由pthread_mutex_lock锁定的mutex
CMutexClass,CEventClass
pthread_mutex_destroy
UNIX-POSIXTHREADS
释放分配给mutex的资源
CMutexClass,CEventClass
CreateEvent
Windows
创建一个Windows事件对象
CEventClass
SetEvent
Windows
设置某一Windows事件对象为有信号状态
CEventClass
pthread_cond_signal
UNIX-POSIXTHREADS
解除由pthread_cond_wait阻塞的某一线程
CEventClass
pthread_cond_wait
UNIX-POSIXTHREADS
基于条件变量进行阻塞
CEventClass
pthread_cond_init
UNIX-POSIXTHREADS
初始化一个条件变量
CEventClass
类CMutexClass
类CMutexClass封装了系统级的mutex函数及一个mutex同步对象,且提供了两个成员函数:
Lock及Unlock。
Lock成员函数锁定一个mutex并把它赋给一个调用线程,mutex一直保持锁定状态直到调用线程使用Unlock成员函数释放它。
任何调用Lock成员函数想获取锁定mutex的线程将被阻塞,并置于低CPU占用的等待状态,直到有线程释放了mutex。
CMutexClass:
:
CMutexClass(void):
m_bCreated(TRUE)
{
#ifdefWINDOWS
m_mutex=CreateMutex(NULL,FALSE,NULL);
if(!
m_mutex)m_bCreated=FALSE;
#else
pthread_mutexattr_tmattr;
pthread_mutexattr_init(&mattr);
pthread_mutex_init(&m_mutex,&mattr);
#endif
memset(&m_owner,0,sizeof(ThreadId_t));
}
CMutexClass:
:
~CMutexClass(void)
{
#ifdefWINDOWS
WaitForSingleObject(m_mutex,INFINITE);
CloseHandle(m_mutex);
#else
pthread_mutex_lock(&m_mutex);
pthread_mutex_unlock(&m_mutex);
pthread_mutex_destroy(&m_mutex);
#endif
}
/**
*
*Lock
*同一线程只能锁定同一mutex一次
*
**/
void
CMutexClass:
:
Lock()
{
ThreadId_tid=CThread:
:
ThreadId();
try{
if(CThread:
:
ThreadIdsEqual(&m_owner,&id))
//mutex已被这个线程锁定
throw"/n/tthesamethreadcannotacquireamutextwice!
/n";
#ifdefWINDOWS
WaitForSingleObject(m_mutex,INFINITE);
#else
pthread_mutex_lock(&m_mutex);
#endif
m_owner=CThread:
:
ThreadId();
}
catch(char*psz)
{
#ifdefWINDOWS
MessageBoxA(NULL,&psz[2],"FatalexceptionCMutexClass:
:
Lock",
MB_ICONHAND);
exit(-1);
#else
cerr<<"FatalexceptionCMutexClass:
:
Lock:
"< #endif } } /** * *Unlock *只有获取该mutex的线程能释放它 * **/ void CMutexClass: : Unlock() { ThreadId_tid=CThread: : ThreadId(); try { if(! CThread: : ThreadIdsEqual(&id,&m_owner)) throw"/n/tonlythethreadthatacquiresamutexcan releaseit! "; memset(&m_owner,0,sizeof(ThreadId_t)); #ifdefWINDOWS ReleaseMutex(m_mutex); #else pthread_mutex_unlock(&m_mutex); #endif } catch(char*psz) { #ifdefWINDOWS MessageBoxA(NULL,&psz[2],"FatalexceptionCMutexClass: : Unlock", MB_ICONHAND); exit(-1); #else cerr<<"FatalexceptionCMutexClass: : Unlock: "< #endif } } --@page{margin: 2cm}P{margin-bottom: 0.21cm}--> 函数 描述 voidCMutexClass() 构造函数 voidLock() 锁定mutex对象或当它阻塞时等待 voidUnlock() 解锁之前阻塞的mutex intg_iStorage=0; CMutexClassMyMutex; voidStoreValue(int*pInt) { MyMutex.Lock(); //它可是“掌门人”喔,一个只允许一个线程。 g_iStorage=*pInt; //受保护的数据,关键代码段。 MyMutex.Unlock(); //解锁,允许其他线程访问g_iStorage } 类CEventClass 类CEventClass封装了Windows事件函数、Windows事件对象、Unix条件变量函数、Unix条件变量。 集成到CEventClass类中的函数分别为Windows下的SetEvent及CreateEvent,Unix下的htread_cond_init、pthread_cond_destroy、pthread_cond_signal、pthread_cond_wait。 在Unix下,为了简单起见,事件同步对象被称为条件变量,在此我们把条件变量及事件对象均称为事件对象。 #include"Thread.h" #include usingnamespacestd; CEventClass: : CEventClass(void): m_bCreated(TRUE) { memset(&m_owner,0,sizeof(ThreadId_t)); #ifdefWINDOWS m_event=CreateEvent(NULL,FALSE,FALSE,NULL); if(! m_event) { m_bCreated=FALSE; } #else pthread_mutexattr_tmattr; pthread_mutexattr_init(&mattr); pthread_mutex_init(&m_lock,&mattr); pthread_cond_init(&m_ready,NULL); #endif } CEventClass: : ~CEventClass(void) { #ifdefWINDOWS CloseHandle(m_event); #else pthread_cond_destroy(&m_ready); pthread_mutex_destroy(&m_lock); #endif } /** * *Set *设置某一事件为有信号状态 * **/ void CEventClass: : Set() { #ifdefWINDOWS SetEvent(m_event); #else pthread_cond_signal(&m_ready); #endif } /** * *Wait *等待一个事件对象为有信号状态,必须在同一线程中与Reset调用成对使用。 * **/ BOOL CEventClass: : Wait() { try { ThreadId_tid=CThread: : ThreadId(); if(CThread: : ThreadIdsEqual(&id,&m_owner)) { throw"/n/tinvalidWaitcall,Waitcannotbecalledmore thanonce" "/n/twithoutacorrespondingcalltoReset! /n"; } ThreadId_tzero; memset(&zero,0,sizeof(ThreadId_t)); if(memcmp(&zero,&m_owner,sizeof(ThreadId_t))! =0) { throw"/n/tanotherthreadisalreadywaitingonthisevent! /n"; } m_owner=CThread: : ThreadId(); #ifdefWINDOWS if(WaitForSingleObject(m_event,INFINITE)! =WAIT_OBJECT_0) { returnFALSE; } #else pthread_mutex_lock(&m_lock); pthread_cond_wait(&m_ready,&m_lock); returnTRUE; #endif } catch(char*psz) { #ifdefWINDOWS MessageBoxA(NULL,&psz[2],"FatalexceptionCEventClass: : Wait", MB_ICONHAND); exit(-1); #else cerr<<"FatalexceptionCEventClass: : Wait: "< #endif } returnTRUE; } /** * *Reset *复位一个事件标志为无信号状态,必须在同一线程中与前面的Wait成对使用。 * **/ void CEventClass: : Reset() { try { ThreadId_tid=CThread: : ThreadId(); if(! CThread: : ThreadIdsEqual(&id,&m_owner)) { throw"/n/tunbalancedcalltoReset,Resetmustbecalled from/n" "/n/tthesameWait-Resetpair! /n"; } memset(&m_owner,0,sizeof(ThreadId_t)); #ifndefWINDOWS pthread_mutex_unlock(&m_lock); #endif } catch(char*psz) { #ifdefWINDOWS MessageBoxA(NULL,&psz[2],"FatalexceptionCEventClass: : Reset", MB_ICONHAND); exit(-1); #else cerr<<"FatalexceptionCEventClass: : Reset: "< #endif } } --@page{margin: 2cm}P{margin-bottom: 0.21cm}--> 函数 描述 voidSet() 设置一个事件状态为有信号,通知阻塞的线程。 BOOLWait() 把调用线程置于阻塞状态,直到事件状态为有信号。 成功返回TRUE,否则返回FALSE。 voidReset() 把一个有信号事件重置为无信号状态。 接收信号的线程使用事件对象的例子: CEventClassevent; . . //线程代码 . . while(bContinueRunning) { event.Wait(); //等待事件发生 //执行某些任务 . . event.Reset(); //重置事件为无信号状态 } . . 向另一线程发信号时使用事件对象的例子: CEventClassevent; . . //改动了一些数据 . . event.Set(); //通知线程一个事件已发生,设置事件为有信号状态。 . . CTask类及非特定的线程 在许多线程编程的示例中,线程处理的数据一般都放在由mutex保护的全局变量中,操纵数据的指令也在集成进线程函数中,我们把这种形式的的线程称为特定异步线程(SAT);理想上来说,数据及对应的处理数据的功能,都应封装进同一对象,我们把这种形式的线程称为同种异步线程(HAT)。 在HAT模式下,线程不是特定的,举例来说,HAT中就没有打印线程及I/O线程,取而代之的是,单一线程能执行这两种任务,因为任务是彻底作为对象来实现的,那就是说,它们包含了数据及必要的功能。 CTask类就是一个采用HAT线程模式的基类。 typedefenum{ TaskStatusNotSubmitted, TaskStatusWaitingOnQueue, TaskStatusBeingProcessed, TaskStatusCompleted}TaskStatus_t; classCTask { private: CMutexClassm_mutex; TaskStatus_tm_state; ThreadId_tm_dwThread; public: voidSetTaskStatus(TaskStatus_tstate) { m_mutex.Lock(); m_state=state; m_mutex.Unlock(); } voidSetId(ThreadId_t*pid) { memcpy(&m_dwThread,pid,sizeof(ThreadId_t)); } /** * *Wait *等待任务完成,或timeoutSeconds秒 * **/ BOOLWait(inttimeoutSeconds) { timeoutSeconds=timeoutSeconds*1000; if(Status()! =TaskStatusCompleted&& timeoutSeconds>0) { Sleep(100); timeoutSeconds=timeoutSeconds-100; } if(Status()==Tas
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 线程 教程