前段日子自己在处理线程的时候遇到同步问题了,当时自己选择使用的是互斥对象Mutex,效果还可以,今天我一同事也遇到了这样的问题,也要实现线程同步,我就给了他一些建议,为以后大家能更好的使用就将自己整理的贴过来了!
http://www.l4nkor.org/read.php/68.htm
VC++中多线程同步方法
当我们多个线程同时运行时就会出现同步问题。这里总结了3种线程同步:
1.利用互斥对象实现线程同步:
HANDLE CreateMutex(
// 安全特性
LPSECURITY_ATTRIBUTES lpMutexAttributes,
// 初始拥有者,TRUE:创建该互斥对象的线程或者 FALSE:该创建线程不获得所创建的互斥对象的所有权
BOOL bInitialOwner,
// 对象名字,为NULL表示匿名对象
LPCTSTR lpName
);
互斥对象属于内核对象,能够确保线程用于对单个资源的互斥访问权;
在主线程创建互斥对象:
HANDLE hMutex;
// 第一个线程,如果是TRUE,表示主线程获得该对象访问权,那么创建互斥对象后必须先利用
// ReleaseMutex来释放互斥对象,不然子线程永远不可能拿到执行权
hMutex=CreateMutex(NULL,FALSE,NULl);
在子线程中,采用函数等待:
// INFINITE表示无限制等待,直到该子线程获得执行,在要保护的代码前添加
WaitForSingleObject(hMutex,INFINITE)
当获得执行权是就有变成有信号状态
执行完成就要释放获得的访问权以给其他子线程访问:
// 记住一点:谁拥有互斥对象谁释放,否则其他线程不能在获得(通过互斥对象的线程ID来判断)
// 另外要注意互斥对象的计数器为0时才能释放访问权ReleaseMutex(hMutex);
这样就可以解决多个线程的访问问题。
总结以下几点:
a.谁拥有互斥对象谁释放
b.互斥对象的计数器为0时才能释放访问权
简单示例:程序实例运行唯一性实现
hMutex=CreateMutex(NULL,TRUE,"cplus");
if(hMutex)
{
if(ERROR_ALREADY_EXISTS==GetLastError())
{
AfxMessageBox("程序已经运行了!");
return FALSE;
}
}
WaitForSingleObject(hMutex,INFINITE);
ReleaseMutex(hMutex);
ReleaseMutex(hMutex);
AfxEnableControlContainer();
2.
事件对象实现线程同步
HANDLE CreateEvent(
// 设置为NULL,即使用默认安全
LPSECURITY_ATTRIBUTES lpEventAttributes,
// TRUE:人工重置,必须使用ResetEvent来时制定事件对象进入非信号状态
// 所有等待的线程都可以同时运行
// FALSE:系统自动重置事件对象为非信号状态
BOOL bManualReset,
// 初始化状态
BOOL bInitialState,
// 事件对象名字,可为匿名对象
LPCTSTR lpName
);
具体实现:
HANDLE m_ghEvent;
在主线程中:
// 创建一个时间对象,系统重置
m_ghEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
// 设置成有信号状态
SetEvent(m_ghEvent);
在子线程函数中采用
WaitForSingleObject(m_ghEvent,INFINITE);
3.临界资源对象实现线程同步
主线程中:
CRITICAL_SECTION g_CS;
InitializeCriticalSection(&g_CS);
主程序结束要记得删除:
DeleteCriticalSection(&g_CS);
在子线程的保护代码前加入:
EnterCriticalSection(&g_CS);
子线程完成后:
LeaveCriticalSection(&g_CS);
3种同步方法的比较
总结:
互斥对象和事件对象----速度较慢
临界资源对象----速度快,但容易进入死锁,是处理多线程首选
这个对多线程进行了详细的讲解,有例子:http://www.vckbase.com/document/viewdoc/?id=1708
加一点线程关闭的资料:http://www.busfly.cn/csdn/post/88.html下面是原文:
VC-终止线程,ExitThread函数,Te r m i n a t e T h r e a d函数,撤消线程,详解
6.5 终止线程的运行
若要终止线程的运行,可以使用下面的方法:
• 线程函数返回(最好使用这种方法)。
• 通过调用E x i t T h r e a d函数,线程将自行撤消(最好不要使用这种方法)。
• 同一个进程或另一个进程中的线程调用Te r m i n a t e T h r e a d函数(应该避免使用这种方法)。
• 包含线程的进程终止运行(应该避免使用这种方法)。
下面将介绍终止线程运行的方法,并且说明线程终止运行时会出现什么情况。
6.5.1 线程函数返回
始终都应该将线程设计成这样的形式,即当想要线程终止运行时,它们就能够返回。这是
确保所有线程资源被正确地清除的唯一办法。
如果线程能够返回,就可以确保下列事项的实现:
• 在线程函数中创建的所有C + +对象均将通过它们的撤消函数正确地撤消。
• 操作系统将正确地释放线程堆栈使用的内存。
• 系统将线程的退出代码(在线程的内核对象中维护)设置为线程函数的返回值。
• 系统将递减线程内核对象的使用计数。
6.5.2 ExitThread函数
可以让线程调用E x i t T h r e a d函数,以便强制线程终止运行:
该函数将终止线程的运行,并导致操作系统清除该线程使用的所有操作系统资源。但是,C + +资源(如C + +类对象)将不被撤消。由于这个原因,最好从线程函数返回,而不是通过调用E x i t T h r e a d来返回(详细说明参见第4章)。
当然,可以使用E x i t T h r e a d的d w E x i t T h r e a d参数告诉系统将线程的退出代码设置为什么。E x i t T h r e a d函数并不返回任何值,因为线程已经终止运行,不能执行更多的代码。
注意终止线程运行的最佳方法是让它的线程函数返回。但是,如果使用本节介绍的方法,应该知道E x i t T h r e a d函数是Wi n d o w s用来撤消线程的函数。如果编写C / C + +代码,那么决不应该调用E x i t T h r e a d。应该使用Visual C++运行期库函数_ e n d t h r e a d e x。如果不使用M i c r o s o f t的Visual C++编译器,你的编译器供应商有它自己的E x i t T h r e a d的替代函数。不管这个替代函数是什么,都必须使用。本章后面将说明_ e n d t h r e a d e x的作用和它的重要性。
6.5.3 Te r m i n a t e T h r e a d函数
调用Te r m i n a t e T h r e a d函数也能够终止线程的运行:
第6章线程的基础知识计计127
与E x i t T h r e a d不同,E x i t T h r e a d总是撤消调用的线程,而Te r m i n a t e T h r e a d能够撤消任何线程。h T h r e a d参数用于标识被终止运行的线程的句柄。当线程终止运行时,它的退出代码成为你作为d w E x i t C o d e参数传递的值。同时,线程的内核对象的使用计数也被递减。
注意Te r m i n a t e T h r e a d函数是异步运行的函数,也就是说,它告诉系统你想要线程终止运行,但是,当函数返回时,不能保证线程被撤消。如果需要确切地知道该线程已经终止运行,必须调用Wa i t F o r S i n g l e O b j e c t (第9章介绍)或者类似的函数,传递线程的
句柄。
设计良好的应用程序从来不使用这个函数,因为被终止运行的线程收不到它被撤消的通知。线程不能正确地清除,并且不能防止自己被撤消。注意当使用返回或调用E x i t T h r e a d的方法撤消线程时,该线程的内存堆栈也被撤消。但是,如果使用Te r m i n a t e T h r e a d,那么在拥有线程的进程终止运行之前,系统不撤消该线程的堆栈。M i c r o s o f t故意用这种方法来实现Te r m i n a t e T h r e a d。如果其他仍然正在执行的线程要引用强制撤消的线程堆栈上的值,那么其他的线程就会出现访问违规的问题。如果将已经撤消的线程的堆栈留在内存中,那么其他线程就可以继续很好地运行。此外,当线程终止运行时, D L L通常接收通知。如果使用Terminate Thread 强迫线程终止,D L L就不接收通知,这能阻止适当的清除(详细信息参见第2 0章)。
6.5.4 在进程终止运行时撤消线程
第4章介绍的E x i t P r o c e s s和Te r m i n a t e P r o c e s s函数也可以用来终止线程的运行。差别在于这些线程将会使终止运行的进程中的所有线程全部终止运行。另外,由于整个进程已经被关闭,进程使用的所有资源肯定已被清除。这当然包括所有线程的堆栈。这两个函数会导致进程中的剩余线程被强制撤消,就像从每个剩余的线程调用Te r m i n a t e T h r e a d一样。显然,这意味着正确的应用程序清除没有发生,即C + +对象撤消函数没有被调用,数据没有转至磁盘等等。
WINDOWS核心编程
线程挂起与恢复:需要在创建线程的时候保存线程句柄
HANDEL hConThread线程句柄
SuspendThread(hConThread);//挂起
ResumeThread(hConThread);//恢复