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被传到这
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的时候,线程的句柄就被系统销毁了,但线程还在,直到结束
函数功能:完成工作后,调用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 );
函数功能: WaiForMultipleObjects函数等待几个线程的激发,当所等待的线程都激发或者时间片用尽而返回。由参数不同而不同。
函数原型:
DWORD WaitForMultipleObjects(
//表示等待几个线程
DWORD nCount,
//输入要等待的线程的名称,前提是一个线程的数组
CONST HANDLE *lpHandles,
//如果这个里面填入true,那么必须所有等待的线程都激发才能返回,如果填false,那么只要有一个handle激发了次函数就能返回
BOOL fWaitAll,
//如果是0,那么到这里就立刻结束了,如果是INFINITE,就无穷等待,直到,要等待的线程都激发为止
DWORD dwMilliSeconds );
Sleep
函数功能:该函数对于指定的时间间隔挂起当前的执行线程。
函数原型:
VOID Sleep(DWORD dwMilliseconds);
//里面填入要挂起的时间间隔,以毫秒为单位
函数功能:该函数对于指定的时间间隔挂起当前的执行线程。
函数原型:
VOID Sleep(DWORD dwMilliseconds);
//里面填入要挂起的时间间隔,以毫秒为单位
WaitForSingleObject
函数功能:当如下情况之一发生时该函数返回:指定对象处于信号态;超时。
函数原型:
DWORD WaitForSingleObject(
//等待对象的线程HANDLE,或者仅仅是一个句柄,如信号量
HANDLE hHandle,
//如果输入一个以毫秒为单位的时间,则等待的最长时间就是那个
当时间片结束时不管是否HANDLE已激活,都返回
如果输入0,则立刻返回
如果输入INFINITE,则无穷等待,直到HANDLE激活为止
DWORD dwMilliseconds
);
函数功能:当如下情况之一发生时该函数返回:指定对象处于信号态;超时。
函数原型:
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 );
函数功能:该函数是创建一个有名或者无名信号对象。(锁定一次现值减一)
函数原型:
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多线程程序设计学习笔记_来碗鱼丸粗面_新浪博客函数功能:该函数是创建有名或者无名的互斥对象。
函数原型:
HANDLE CreateMutex(
//安全属性,NULL表示使用默认值
LPSECURITY_ATTRIBUTES lpMutexAttributes,
//填入TRUE表示此互斥量可以被调用
BOOL bInitialOwner,
//互斥量的名称,在这里可以自己指定
LPCTSTR lpName
);
ReleaseMutex
函数功能:该函数放弃指定互斥对象的拥有权。每使用一次,MUTEX引用计数自加1;每释放一次,MUTEX引用计数自减1,当引用计数减到0时,此互斥量销毁,这一点如果使用CloseHandle(),也可以达到相同的效果,如果只引用了一次MUTEX而同时使用了ReleaseMutex(),和CloseHandle(),那么这个MUTEX直接销毁了。
函数原型:
BOOL ReleaseMutex(
//想要释放的信号量句柄
HANDLE hMutex
);
函数功能:该函数放弃指定互斥对象的拥有权。每使用一次,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; );
函数功能:提供一个返回的线程结束代码,用以判断是否线程结束了。
通过调用此函数,同时使用在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中得到了弥补。
定义临界区变量
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函数中调用,使得程序支持包含OLE控件
如果是跳出InitInstance()之后再运行自己的程序有两种情况:
1 如果是基于DOC/VIEW的,就在CView::OnInitUpdate()函数里执行一个自定义函数
2 如果是基于对话框的,就在CDialog::OnInitDialgo()函数里执行一个自定义函数
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:应用程序类”。
- WIN32 API 多线程编程学习笔记
- 多线程编程win32 API
- [笔记]Win32多线程API
- 二. Win32 API 多线程编程
- Win32 API多线程编程例程
- win32多线程学习笔记
- Win32编程学习笔记
- Win32 API下的多线程编程
- Win32 API下的多线程编程
- Win32 API下的多线程编程
- Win32 API下的多线程编程
- Win32 API 多线程编程例程一
- Win32 API 多线程编程例程二
- WIN32多线程程序设计学习笔记
- 学习笔记 -- Win32 多线程程序设计
- Win32 API编程笔记(转)
- Win32编程day01 学习笔记
- GCD 多线程API编程笔记
- HttpWatch工具简介及使用技巧
- 在MyEclipse当中安装jbpm
- JAVA面试题解惑系列(一)——类的初始化顺序
- 在十六进制字符串与数值类型之间转换
- SQL2000的sysindexes视图在SQL2005中的另类表现
- WIN32 API 多线程编程学习笔记
- 数据结构学习——查找表
- .Net compact framework 界面自适应输入法
- Linux服务器配置手册
- mysql JDBC URL参数解析
- 解决令人抓狂的zend studio 7代码提示(content Assist)速度慢问题
- [Linux]在Linux上部署Java开发环境笔记(三)-- 补充:Linux中安装Oracle10g(标准版)
- PHP图表制作工具集
- SQL访问顾问(SQL Access Advisor)之一: 概要