笔记:多线程

来源:互联网 发布:中国网络远程学校 编辑:程序博客网 时间:2024/05/22 14:06

1.基本函数

CreatThread()

HANDLE WINAPI CreateThread(  LPSECURITY_ATTRIBUTES lpThreadAttributes,  SIZE_T dwStackSize,  LPTHREAD_START_ROUTINE lpStartAddress,  LPVOID lpParameter,  DWORDdw CreationFlags,  LPDWORD pThreadId);

函数说明:

  • 参数1,线程内核对象的安全属性,一般传入NULL表示使用默认设置
  • 参数2,线程栈空间大小。传入0表示使用默认大小(1MB)
  • 参数3,新线程所执行的线程函数地址,多个线程可以使用同一个函数地址
  • 参数4,传给线程函数的参数,无参数时为NULL
  • 参数5,控制线程的标志,0表示线程创建之后立即就可以进行调度;CREATE_SUSPENDED表示创建挂起的线程,暂停执行,此时线程无法调度,直到调用ResumeThread()
  • 参数6,返回线程的ID,不需要返回则为NULL
  • 返回值,成功则返回线程的句柄,失败返回NULL

C标准库没考虑多线程运行的情况,因此多线程调用C标准库时可能造成数据被覆盖篡改的情况。为避免这个问题,可以使用_beginthreadex()函数来创建线程,生成每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用


WaitForSingleObject()

DWORD WINAPI WaitForSingleObject(  HANDLE hHandle,  DWORD dwMilliseconds);

函数说明:等待对象被触发
- 参数1,对象句柄,可指定一系列对象
- 参数2,最长等待时间,以毫秒为单位,0为立即返回,INFINITE表示无限等待
- 返回值,WAIT_OBJECT_0,指定的时间内对象被触发;WAIT_TIMEOUT,超过最长等待时间对象仍未被触发返回;WAIT_FAILED传入参数有错误

线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以WaitForSingleObject()来等待一个线程结束运行

  • 内核对象被占用,处于未触发,无信号状态
  • 内核对象未被占用时,处于触发,有信号状态

WaitForMultipleObjects()

DWORD WaitForMultipleObjects(DWORD nCount,const HANDLE* lpHandles,BOOL bWaitAll,DWORD dwMilliseconds);

函数说明:等待多个内核对象触发返回

  • 参数1,句柄的数量 最大值为MAXIMUM_WAIT_OBJECTS(64)
  • 参数2,句柄数组的指针, 类型可以为(Event,Mutex,Process,Thread,Semaphore )数组
  • 参数3,等待的类型,如果为TRUE 则等待所有信号量有效再返回,FALSE 当有其中一个信号量有效时就返回
  • 参数4,INFINITE为无限等待直到所有对象触发,0为立即返回,继续向下执行
  • 返回值,WAIT_OBJECT_0到WAIT_OBJECT_0 + nCount - 1,如果bWaitAll为TRUE,则返回值表明所有指定对象的状态信号。如果bWaitAll为FALSE,其返回值减去WAIT_OBJECT_0 就是参数lpHandles数组的序号。如果同时有多个内核对象被触发,这个函数返回的只是其中序号最小的那个

2.关键段

CRITICAL_SECTION

  • 初始化函数
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
  • 销毁函数
void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
  • 进入关键段
void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
  • 离开关键段
void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);

关键段会记录拥有该关键段的线程句柄即关键段是有“线程所有权”,拥有关键段的线程可多次进入关键段,相关参数会记录进入关键段的次数,当该参数变成0时,系统会更新关键段,将等待中的线程变为可调度状态


3.事件Event

创建事件CreateEvent

HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOLbManua lReset, BOOL bInitialState, LPCTSTR lpName);
  • 参数1,安全控制参数,一般直接传入NULL
  • 参数2,置位参数,TRUE表示手动置位,FALSE表示自动置位。如果为自动置位,则对该事件调用WaitForSingleObject()后会自动调用ResetEvent()使事件变成未触发状态。
  • 参数3,事件的初始状态,TRUE表示已触发,FALSE表示未触发
  • 参数4,事件的名称,NULL表示匿名事件

根据事件名获取事件句柄OpenEvent

HANDLE OpenEvent( DWORDdwDesiredAccess, BOOLbInheritHandle, LPCTSTRlpName     //名称);
  • 参数1,访问权限,对事件一般传入EVENT_ALL_ACCESS
  • 参数2,事件句柄继承性,一般传入TRUE即可
  • 参数3,名称,不同进程中的各线程可以通过名称来确保它们访问同一个事件

触发事件SetEvent

BOOL SetEvent(HANDLE hEvent);

设置事件为可触发状态(未被占用、有信号)
和WaitSingleObject配合使用,事件自动置位(FALSE)时,接收到SetEvent的信号后,系统自动将事件重置为不可触发状态;而事件手动置位(TRUE)时,需要手动调用ResetEvent重置事件的状态


设置事件未触发ResetEvent

BOOL ResetEvent(HANDLE hEvent);

事件的清理和销毁使用CloseHandle()

  1. 事件是内核对象,事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发
  2. 事件可以由SetEvent()来触发,由ResetEvent()来设成未触发。还可以由PulseEvent()来发出一个事件脉冲
  3. 事件可以解决线程间同步问题,因此也能解决互斥问题

4.互斥量Mutex

创建互斥量CreateMutex

HANDLE CreateMutex(  LPSECURITY_ATTRIBUTES lpMutexAttributes,  BOOL bInitialOwner,       LPCTSTR lpName);
  • 参数1,安全控制,一般直接传入NULL
  • 参数2,确定互斥量的初始拥有者,TRUE表示由创建它的线程拥有,此时处于未触发状态;FALSE表示互斥量不被任何线程占用,处于触发状态
  • 参数3,设置互斥量的名称,可以为NULL

打开互斥量OpenMutex

HANDLE OpenMutex( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName     //名称);
  • 参数1,访问权限,对互斥量一般传入MUTEX_ALL_ACCESS
  • 参数2,互斥量句柄继承性,一般传入TRUE
  • 参数3,互斥量名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过名称找到这个互斥量

释放互斥量ReleaseMutex

BOOL ReleaseMutex (HANDLE hMutex)

访问结束后,线程调用释放函数,其他线程可以访问互斥量

互斥量是内核对象,清理互斥量使用CloseHandle()


  1. 互斥量是内核对象,它与关键段都有“线程所有权”所以不能用于线程的同步
  2. 互斥量能够用于多个进程之间线程互斥问题,当拥有互斥量的线程意外终止时,互斥量会被系统回收,确保其他线程可以继续使用

4.信号量Semaphore

创建信号量CreateSemaphore

HANDLE CreateSemaphore(  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  LONG lInitialCount,  LONG lMaximumCount,  LPCTSTR lpName);
  • 参数1,安全控制,一般为NULL
  • 参数2,初始资源数量
  • 参数3,最大并发数量
  • 参数4,信号量名称,NULL表示匿名信号量

打开信号量OpenSemaphore

HANDLE OpenSemaphore(  DWORD dwDesiredAccess,  BOOL bInheritHandle,  LPCTSTR lpName);
  • 参数1,访问权限,对一般传入SEMAPHORE_ALL_ACCESS
  • 参数2,信号量句柄继承性,一般传入TRUE
  • 参数3,信号量名称

增加信号量资源计数ReleaseSemaphore

BOOL ReleaseSemaphore(  HANDLE hSemaphore,  LONG lReleaseCount,    LPLONG lpPreviousCount );
  • 参数1,信号量句柄
  • 参数2,资源增加个数,大于0且小于最大资源数
  • 参数3,传出增加前的资源计数,NULL为不用传出

  1. 信号量是内核对象,使用CloseHandle()清理和销毁
  2. 当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发
0 0
原创粉丝点击