WIN32 API 多线程编程学习笔记

来源:互联网 发布:崔杼杀史官 知乎 编辑:程序博客网 时间:2024/04/26 20:06

                Win32API多线程程序设计学习笔记
CreateThread
函数功能:该函数创建一个在调用进程的地址空间中执行的线程。
函数原型: 
HANDLE  CreateThread ( 
LPSECURITY_ATTRIBUTES lpThreadAttributes,
//描述安全性,用NULL表示使用缺省值,推荐
DWORD dwStackSize, 
//新线程拥有自己的堆栈,0表示使用缺省值1MB,推荐
LPTHREAD_START_ROUTINE  lpStartAddress, 
//新线程的起始地址,放线程函数名称
LPVOID  lpParameter,
//此值被传送到线程函数去作为参数
DWORD dwCreationFlags,
//允许产生一个暂时挂起的线程,默认是立即开始执行
LPDWORD lpThreadld  );
//新线程的ID被传到这
 
CloseHandle
函数功能:完成工作后,调用CloseHandle释放核心对象
函数原型:
BOOL CloseHandle(
        //代表一个已打开的对象HANDLE
        HANDLE hObject;
);
PS:  closehandle()在线程开始以后就调用了,这时候,它就把线程的句柄给关闭了,而线程还在继续运行,直到线程运行完毕。closehandel就是把线程的引用计数减一,当减到0的时候,线程的句柄就被系统销毁了,但线程还在,直到结束
 
WaitForMultipleObjects
函数功能:  WaiForMultipleObjects函数等待几个线程的激发,当所等待的线程都激发或者时间片用尽而返回。由参数不同而不同。
函数原型: 
DWORD WaitForMultipleObjects(
          //表示等待几个线程
DWORD nCount,
//输入要等待的线程的名称,前提是一个线程的数组
CONST HANDLE *lpHandles,
//如果这个里面填入true,那么必须所有等待的线程都激发才能返回,如果填false,那么只要有一个handle激发了次函数就能返回
BOOL fWaitAll,
//如果是0,那么到这里就立刻结束了,如果是INFINITE,就无穷等待,直到,要等待的线程都激发为止
DWORD dwMilliSeconds  );
 
Sleep
函数功能:该函数对于指定的时间间隔挂起当前的执行线程。
函数原型:
VOID Sleep(DWORD dwMilliseconds);
//里面填入要挂起的时间间隔,以毫秒为单位
 
 
WaitForSingleObject
函数功能:当如下情况之一发生时该函数返回:指定对象处于信号态;超时。
函数原型: 
DWORD  WaitForSingleObject( 
          //等待对象的线程HANDLE,或者仅仅是一个句柄,如信号量
HANDLE hHandle,
//如果输入一个以毫秒为单位的时间,则等待的最长时间就是那个
当时间片结束时不管是否HANDLE已激活,都返回
  如果输入0,则立刻返回
  如果输入INFINITE,则无穷等待,直到HANDLE激活为止
DWORD dwMilliseconds
);
 
CreatSemaphore
函数功能:该函数是创建一个有名或者无名信号对象。(锁定一次现值减一)
函数原型:
HANDLE CreateSemaphore(
//安全属性,NULL表示默认属性,推荐
LPSECURITY_ATTRIBUTES lpAttributes,
//信号量的初值,必须大于等于0,小于等于所定义的最大数量
LONG lInitialCount,
//信号量的最大值,是自己定义的,
LONG lMaximumCount,
//信号量的名称,如“FULL”,如果是NULL,则此信号量无名称
LPCTSTR lpName   );

ReleaseSemaphore
函数功能:该函数将指定信号对象的计数增加一个指定的数量。
函数原型:
ReleaseSemaphore(
          //需要释放的信号量的句柄
        HANDLE hSemaphore,
          //信号量现值的增额,不可以是负值或是0
        LONG lReleaseCount,
          //返回信号量原来的现值
        LPLONG lpPreviousCount
);
一个信号量,只要锁定一次就会自减,只要释放一次,就会自加
 
CreateMutex
函数功能:该函数是创建有名或者无名的互斥对象。
函数原型:
HANDLE CreateMutex( 
//安全属性,NULL表示使用默认值
LPSECURITY_ATTRIBUTES lpMutexAttributes,
//填入TRUE表示此互斥量可以被调用
BOOL bInitialOwner,
//互斥量的名称,在这里可以自己指定
LPCTSTR lpName
);
来源:(http://blog.sina.com.cn/s/blog_499b249c010003nw.html) - Win32API多线程程序设计学习笔记_来碗鱼丸粗面_新浪博客
 
ReleaseMutex
函数功能:该函数放弃指定互斥对象的拥有权。每使用一次,MUTEX引用计数自加1;每释放一次,MUTEX引用计数自减1,当引用计数减到0时,此互斥量销毁,这一点如果使用CloseHandle(),也可以达到相同的效果,如果只引用了一次MUTEX而同时使用了ReleaseMutex(),和CloseHandle(),那么这个MUTEX直接销毁了。
函数原型:
BOOL ReleaseMutex(
              //想要释放的信号量句柄
HANDLE hMutex
);
 
GetExitCodeThread
函数功能:提供一个返回的线程结束代码,用以判断是否线程结束了。
通过调用此函数,同时使用在createthread中获得的线程ID作为参数,就可以得到线程的结束代码。传回的值为TRUE或FALSE。
          如果线程已结束,那么线程的结束代码会被放在lpExitCode参数中带回来,如果线程尚未结束,那么带回来的值是STILL_ACTIVE
函数原型:
BOOL GetExitCodeThread(
          //这里放由creatThread传回的线程ID
              HANDLE hThread;
              //指向一个DWORD用以接受结束代码(EXITCODE)
              LPWORD lpExitCode;   );

 事件

  事件(Event)是WIN32提供的最灵活的线程间同步方式,事件可以处于激发状态(signaled or true)或未激发状态(unsignal or false)。根据状态变迁方式的不同,事件可分为两类:

  (1)手动设置:这种对象只可能用程序手动设置,在需要该事件或者事件发生时,采用SetEvent及ResetEvent来进行设置。

  (2)自动恢复:一旦事件发生并被处理后,自动恢复到没有事件状态,不需要再次设置。

  创建事件的函数原型为:

HANDLE CreateEvent(
 LPSECURITY_ATTRIBUTES lpEventAttributes,
 // SECURITY_ATTRIBUTES结构指针,可为NULL
 BOOL bManualReset,
 // 手动/自动
 // TRUE:在WaitForSingleObject后必须手动调用ResetEvent清除信号
 // FALSE:在WaitForSingleObject后,系统自动清除事件信号
 BOOL bInitialState, //初始状态
 LPCTSTR lpName //事件的名称
);
  使用"事件"机制应注意以下事项:

  (1)如果跨进程访问事件,必须对事件命名,在对事件命名的时候,要注意不要与系统命名空间中的其它全局命名对象冲突;

  (2)事件是否要自动恢复;

  (3)事件的初始状态设置。

  由于event对象属于内核对象,故进程B可以调用OpenEvent函数通过对象的名字获得进程A中event对象的句柄,然后将这个句柄用于ResetEvent、SetEvent和WaitForMultipleObjects等函数中。此法可以实现一个进程的线程控制另一进程中线程的运行,例如:

HANDLE hEvent=OpenEvent(EVENT_ALL_ACCESS,true,"MyEvent");
ResetEvent(hEvent);
 
 
临界区

  定义临界区变量

CRITICAL_SECTION gCriticalSection;
  通常情况下,CRITICAL_SECTION结构体应该被定义为全局变量,以便于进程中的所有线程方便地按照变量名来引用该结构体。

  初始化临界区

VOID WINAPI InitializeCriticalSection(
 LPCRITICAL_SECTION lpCriticalSection
 //指向程序员定义的CRITICAL_SECTION变量
);
  该函数用于对pcs所指的CRITICAL_SECTION结构体进行初始化。该函数只是设置了一些成员变量,它的运行一般不会失败,因此它采用了VOID类型的返回值。该函数必须在任何线程调用EnterCriticalSection函数之前被调用,如果一个线程试图进入一个未初始化的CRTICAL_SECTION,那么结果将是很难预计的。

  删除临界区

VOID WINAPI DeleteCriticalSection(
 LPCRITICAL_SECTION lpCriticalSection
 //指向一个不再需要的CRITICAL_SECTION变量
);
  进入临界区

VOID WINAPI EnterCriticalSection(
 LPCRITICAL_SECTION lpCriticalSection
 //指向一个你即将锁定的CRITICAL_SECTION变量
);
  离开临界区

VOID WINAPI LeaveCriticalSection(
 LPCRITICAL_SECTION lpCriticalSection
 //指向一个你即将离开的CRITICAL_SECTION变量
);
  使用临界区编程的一般方法是:

void UpdateData()
{
 EnterCriticalSection(&gCriticalSection);
 ...//do something
 LeaveCriticalSection(&gCriticalSection);
}
  关于临界区的使用,有下列注意点:

  (1)每个共享资源使用一个CRITICAL_SECTION变量;

  (2)不要长时间运行关键代码段,当一个关键代码段长时间运行时,其他线程就会进入等待状态,这会降低应用程序的运行性能;

  (3)如果需要同时访问多个资源,则可能连续调用EnterCriticalSection;

  (4)Critical Section不是OS核心对象,如果进入临界区的线程"挂"了,将无法释放临界资源。这个缺点在Mutex中得到了弥补。
 
void AfxEnableControlContainer( )
在应用程序对象的InitInstance函数中调用,使得程序支持包含OLE控件
 
 
如果是跳出InitInstance()之后再运行自己的程序有两种情况:
1 如果是基于DOC/VIEW的,就在CView::OnInitUpdate()函数里执行一个自定义函数
2 如果是基于对话框的,就在CDialog::OnInitDialgo()函数里执行一个自定义函数
 

CWinApp::InitInstance

virtual BOOL InitInstance( );

返回值

如果初始化成功,则返回非零值;否则返回0

注释

Windows允许在同一时刻运行程序的几份拷贝。在概念上,应用程序的初始化可以被分为两个部分:一次性的应用程序初始化工作,这些在应用程序第一次运行时完成,以及实例的初始化工作,每次运行程序的一个拷贝时都会执行这些操作,包括第一次运行时。框架中WinMain实现调用这个函数。

重载InitInstance以初始化在Windows下运行的应用程序的每个新实例。通常,你重载InitInstance以构造主窗口对象并设置CWinThread::m_pMainWnd数据成员,使其指向这个窗口。有关重载这个成员函数的更多信息参见“Visual C++ 程序员指南中的CWinApp:应用程序类

来源:(http://blog.sina.com.cn/s/blog_499b249c010003nw.html) - Win32API多线程程序设计学习笔记_来碗鱼丸粗面_新浪博客

原创粉丝点击