在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)
下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?
线程函数:
while(!bTerminate)
{
// 从一个链表中读取信息并且插入到CListCtrl中
// CListCtrl的句柄是通过线程参数传递进来的
for(;;)
{
ReadInfoFromList();
InsertToCListCtrl();
}
}
}
主线程中使用CreateThread启动线程。
当想终止子线程时,在主线程中:
bTerminate = TRUE;
WaitForSingleObject(threadHandle, INFINITE);
可是,以运行到WaitForSingleObject,子线程就Crash了。
为什么呢?
问题原因:
后来我终于在InsertItem的反汇编中发现了如下的代码
call dword ptr [__imp__SendMessageA@16 (7C141B54h)]
可见,InsertItem是必须借助消息循环来完成任务的。如果我们在主线程中WaitForSingleObject了,必然导致主线程阻塞,也就导致了消息循环的阻塞,最终导致工作线程Crash掉了*_*
解决方案:
为了解决在主线程中Wait的问题,微软专门设计了一个函数MsgWaitForMultipleObjects,这个函数即可以等待信号(thread,event,mutex等等),也可以等待消息(MSG)。即不论有信号被激发或者有消息到来,此函数都可以返回。呵呵,那么我的解决办法也就出来了。
将上面的WaitForSingleObject用下面的代码替换:
{
DWORD result ;
MSG msg ;
result = MsgWaitForMultipleObjects(1, &readThreadHandle,
FALSE, INFINITE, QS_ALLINPUT);
if (result == (WAIT_OBJECT_0))
{
break;
}
else
{
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
DispatchMessage(&msg);
}
}
总结:
如果在工作线程中有可能涉及到了消息驱动的API,那么不能在主线程中使用WaitForSingleObject一类函数,而必须使用上述的方案。
在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)的更多相关文章
- Linux 下子线程 exit code 在主线程中的使用
Linux线程函数原型是这样的: void* thread_fun(void* arg) 它的返回值是 空类型指针,入口参数也是 空类型指针.那么线程的 exit code 也应该是 void * 类 ...
- [原]unity中WWW isDone方法只能在主线程中调用
项目中要使用动态加载,原计划是生成WWW对象后,放到一个容器里.由一个独立线程轮询容器里的对象,如果www.isDone为true时,回调一个接口把结果交给请求方. new Thread( new T ...
- 主线程中也不绝对安全的 UI 操作
从最初开始学习 iOS 的时候,我们就被告知 UI 操作一定要放在主线程进行.这是因为 UIKit 的方法不是线程安全的,保证线程安全需要极大的开销.那么问题来了,在主线程中进行 UI 操作一定是安全 ...
- 用Handler的post()方法来传递线程中的代码段到主线程中执行
自定义的线程中是不能更新UI的,但是如果遇到更新UI的事情,我们可以用handler的post()方法来将更新UI的方法体,直接传送到主线程中,这样就能直接更新UI了.Handler的post()方法 ...
- android4.0以上访问网络不能在主线程中进行以及在线程中操作UI的解决方法
MONO 调用一个线程操作UI 然后报Only the original thread that created a view hierarchy can touch its views.错误 goo ...
- Android中,子线程使用主线程中的组件出现问题的解决方法
Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行 ...
- httpUrlConnection连接网络的用法(用到了handle传递消息,在主线程中更新UI)
由于httpclient在Android5.0以后已经过时,所以官方推荐使用httpUrlConnection来连接网络,现将该连接的基本方法展示,如下 注意:记得加入<uses-permiss ...
- 在非主线程中更新UI
在非主线程中调用了showMessage方法,结果报错:Can't create handler inside thread that has not called Looper.prepare() ...
- Java线程和多线程(四)——主线程中的异常
作为Java的开发者,在运行程序的时候会碰到主线程抛异常的情况.如果开发者使用Java的IDE比如Eclipse或者Intellij IDEA的话,可能是不需要直接面对这个问提的,因为IDE会处理运行 ...
随机推荐
- 语音转文字小工具开发Python
# -*- coding: utf- -*- import requests import re import os import time from aip import AipSpeech fro ...
- java基本编译
1.java语言严格区分大小写:1个源文件其中最多只能有一个public类:源文件必须和public类同名:每个类对应一个class字节码,且同名. 2.编译. javac -d dir Hell ...
- C#枚举类型转换
string 转 enum (自己定义的枚举类型)(Enum.Parse(typeof(自己定义的枚举类型), 待转字符串)); enum 转 string enum.Getname(typeof(自 ...
- 移动端优化 && 清除移动端网站点击a标签时闪现的边框或遮罩层(CSS) && 移动端点击 && 文字不可选择
在移动端网站,当你点击加了a标签的文字或图片时,该元素的周围会闪现一个蓝色的边框,在微信上的网站就是如此:而有的浏览器会闪现一个半透明遮罩层,比如移动端的Chrome浏览器,其实这些特效无非就是为 ...
- PHP 对字符串 进行填充
1.str_pad — 使用另一个字符串填充字符串为指定长度 . 我觉得str_pad可以满足普通的数字,字符串的简单填充. string str_pad ( string $input , int ...
- Installing Vim 8.0 on Ubuntu 16.04 and Linux Mint 18
sudo add-apt-repository ppa:jonathonf/vim sudo apt update sudo apt install vim uninstall sudo apt re ...
- Oracle数据库调优总结
oracle采用物理读和逻辑读,第一次查询数据库采用的是物理读,以后如果使用相同的sql语句查询,那么它会采用逻辑读,直接从内存中读取数据. 采用执行计划查看执行顺序和耗时:一般查看object na ...
- 话说C语言的关键字volatile
最近搞NVMe驱动需求分析,对volatile这个单词实在是再熟悉不过了. 而在C语言中,有一个关键字就叫做volatile, 其字面意思是"挥发性的, 不稳定的,可改变的". 那 ...
- maven多模块下新建子模块
选中parent模块,右键选择new---others 选择Maven---Maven Module,点击下一步 填写Module Name,其他默认,点击下一步 默认,下一步 默认,点击完成
- shell -- sample -- 关闭tomcat
#!/bin/bash process_name="org.apache.catalina.startup.Bootstrap" shutdown_call= function s ...