线程间同步控制的方法.ppt_第1页
线程间同步控制的方法.ppt_第2页
线程间同步控制的方法.ppt_第3页
线程间同步控制的方法.ppt_第4页
线程间同步控制的方法.ppt_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、面向对象程序设计II,本章授课内容,线程同步概述 临界区对象 互斥函数 事件内核对象 信号量内核对象 互斥内核对象,线程同步概述,线程同步 在应用程序中使用多线程的好处是每个线程都可以异步执行。 线程的异步特性意味着必须协调对资源(如文件句柄、网络连接和内存)的访问。否则,两个或更多的线程可能在同一时间访问相同的资源,而每个线程都不知道其他线程的操作。结果将产生不可预知的数据损坏。 线程同步就是要保证在一个线程占有公共资源的时候,其他的线程不会再次占有这个资源。线程同步问题就是要保证整个对资源存取过程的独占性。,线程同步概述,#include #include #include int g_n

2、Count1 = 0; int g_nCount2 = 0; BOOL g_bContinue = TRUE; UINT _stdcall ThreadFunc(LPVOID); int main(int argc, char* argv) UINT uId; HANDLE h2; h0 = (HANDLE):_beginthreadex(NULL, 0, ThreadFunc, NULL, 0, ,UINT _stdcall ThreadFunc(LPVOID) while(g_bContinue) g_nCount1+; g_nCount2+; return 0; ,临界区对象,临界区对象

3、 临界区对象是定义在数据段中的一个CRITICAL_SECTION结构,windows内部使用这个结构记录信息,确保在同一个时间只有一个线程访问数据段中的数据。 Windows只允许一个线程进入临界区,所以在线程申请进入临界区的时候,如果另一个线程存在于临界区的话,另一个线程就会一直等待下去,直到其他的线程离开临界区为止。,临界区对象,临界区对象初始化 函数原型 编程的时候,要把临界区对象定义在想保护的数据段中,然后在任何线程使用此临界区对象之前对它进行初始化。,void WINAPI InitializeCriticalSection( _out LPCRITICAL_SECTION lpC

4、riticalSection );,CRITICAL_SECTION cs InitializeCriticalSection(,临界区对象,使用临界区对象,:EnterCriticalSection(,临界区(关键代码段),void WINAPI EnterCriticalSection( _inout LPCRITICAL_SECTION lpCriticalSection );,void WINAPI LeaveCriticalSection( _inout LPCRITICAL_SECTION lpCriticalSection );,#include #include #includ

5、e BOOL g_bContinue = TRUE; int g_nCount1 = 0; int g_nCount2 = 0; CRITICAL_SECTION g_cs; / 对存在同步问题的代码段使用临界区对象 UINT _stdcall ThreadFunc(LPVOID); int main(int argc, char* argv) UINT uId; HANDLE h2; / 初始化临界区对象 :InitializeCriticalSection( ,UINT _stdcall ThreadFunc(LPVOID) while(g_bContinue) :EnterCritica

6、lSection( ,事件内核对象,事件内核对象(event) event是一种抽象的内核对象,它有未受信(nosignaled)和受信(signaled)两种状态,编程人员可以使用WaitForSingleObject函数等待其变成受信状态。 事件对象可以进行同进程的线程间和不同进程的线程间的同步与通信。 事件内核对象包含一个使用计数,一个布尔值,来指明这个事件是个自动重置事件还是人工重置事件,事件内核对象,CreateEvent函数,HANDLE WINAPI CreateEvent( _in LPSECURITY_ATTRIBUTES lpEventAttributes, _in BOO

7、L bManualReset, _in BOOL bInitialState, _in LPCTSTR lpName );,指定是否需要手动重置事件对象为未受信状态,指定事件对象创建时的初始状态,事件对象的名称,事件内核对象,OpenEvent函数 可以通过OpenEvent根据对象名来获取此内核对象的句柄,从而和事件对象进行通信。,HANDLE WINAPI OpenEvent( _in DWORD dwDesiredAccess, _in BOOL bInheritHandle, _in LPCTSTR lpName );,事件内核对象,设置事件对象的状态 SetEvent设置事件对象为受

8、信状态 ResetEvent设置事件对象为非受信状态,BOOL WINAPI SetEvent( _in HANDLE hEvent );,BOOL WINAPI ResetEvent( _in HANDLE hEvent );,#include #include #include HANDLE g_hEvent; UINT _stdcall ChildFunc(LPVOID); int main(int argc, char* argv) HANDLE hChildThread; UINT uId; / 创建一个自动重置的(auto-reset events),未受信的(nonsignale

9、d)事件内核对象 g_hEvent = :CreateEvent(NULL, FALSE, FALSE, NULL); hChildThread = (HANDLE):_beginthreadex(NULL, 0, ChildFunc, NULL, 0, ,信号量内核对象,信号量内核对象(semaphore) Semaphore允许多个线程在同一时刻访问统一资源,但是需要限制在同一时刻访问此资源的最大线程数目。 一般将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就减1,只要当前可用资源计数大于0时,就可以发出信号量。,HANDLE WINAPI Crea

10、teSemaphore( _in LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, _in LONG lInitialCount, _in LONG lMaximumCount, _in LPCTSTR lpName );,信号量内核对象,信号量使用规则如下: 当资源的数量大于0时,发出信号量信号 当前资源数目等于0时,不发出信号量信号 当前资源数量不能为负值 当前资源数量不能大于最大资源数量。,(a),(b),(c),(d),信号量内核对象,信号量控制 可以通过openSemaphore函数打开其他进程中的信号量对象。 当线程离开对共享资源的处理时,必

11、须通过releaseSemaphore来增加当前信号量对象的可用资源计数,HANDLE WINAPI OpenSemaphore( _in DWORD dwDesiredAccess, _in BOOL bInheritHandle, _in LPCTSTR lpName );,BOOL WINAPI ReleaseSemaphore( _in HANDLE hSemaphore, _in LONG lReleaseCount, _out LPLONG lpPreviousCount );,#include #include #include HANDLE g_hSemaphore; UINT

12、 _stdcall ChildFunc1(LPVOID) :WaitForSingleObject(g_hSemaphore, INFINITE); printf( Child thread1 is working. n); :ReleaseSemaphore(g_hSemaphore, 1,NULL ); return 0; UINT _stdcall ChildFunc2(LPVOID) :WaitForSingleObject(g_hSemaphore, INFINITE); printf( Child thread2 is working. n); :ReleaseSemaphore(

13、g_hSemaphore, 1,NULL ); return 0; UINT _stdcall ChildFunc3(LPVOID) :WaitForSingleObject(g_hSemaphore, INFINITE); printf( Child thread3 is working. n); :ReleaseSemaphore(g_hSemaphore, 1,NULL ); return 0; UINT _stdcall ChildFunc4(LPVOID) :WaitForSingleObject(g_hSemaphore, INFINITE); printf( Child thre

14、ad4 is working. n); :ReleaseSemaphore(g_hSemaphore, 1,NULL ); return 0; ,int main(int argc, char* argv) unsigned long uId; g_hSemaphore = :CreateSemaphore(NULL, 2, 2, NULL); HANDLE ths1 = :CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ChildFunc1, NULL, 0, ,互斥内核对象,互斥(mutex)内核对象 mutex确保线程可以互斥地访问一个资源。

15、Mutex包含一个引用计数,一个线程id和一个递归计数器。 Mutex的行为特征与临界区相同,区别在于mutex属于内核对象,临界区属于用户模式对象。 互斥对象的运行速度比临界区要慢,但是不同的进程中的多个线程可以通过mutex名来访问同一个mutex 对象,互斥内核对象,互斥(mutex)内核对象 线程id表示系统中正在拥有互斥对象的线程,递归计数器指明这个线程拥有互斥对象的次数。 互斥对象的用途很多,是最常用的内核对象之一,一般使用互斥对象来保护多个进程访问的内存块,互斥对象能够保证线程可以独占式地访问内存块,防止破坏内存中的数据,保护数据的完整性。,互斥内核对象,互斥(mutex)内核对

16、象,HANDLE WINAPI CreateMutex( _in LPSECURITY_ATTRIBUTES lpMutexAttributes, _in BOOL bInitialOwner, _in LPCTSTR lpName );,HANDLE WINAPI OpenMutex( _in DWORD dwDesiredAccess, _in BOOL bInheritHandle, _in LPCTSTR lpName );,BOOL WINAPI ReleaseMutex( _in HANDLE hMutex );,互斥内核对象,Mutex类,class Mutex public:

17、Mutex(); Mutex(const char* nm); void create(const char* nm); unsigned long* getMutexHandle(); string getName(); void release(); Mutex(); private: unsigned long* m_hMutex; string m_strName; ;,Mutex:Mutex() m_hMutex = NULL; m_strName = ; Mutex:Mutex(const char* nm) m_strName = nm; m_hMutex = (unsigned long*)CreateMutex(NULL,FALSE,nm); void Mutex:create(const char* nm) if(m_hMutex != NULL) CloseHandle(m_hMutex); m_hMutex = NULL; m_strName = nm; m_hMutex = (unsigned

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论