[经验分享]挑战不可能的任务,如何唤醒或者退出被阻塞,休眠的线程,非TerminateXXX方法

KeSummer 2008-05-29 10:10:27
很早之前在CSDN上遇到这个问题:
相关帖子:
http://topic.csdn.net/u/20071202/13/3a9bffdd-f2bd-4fec-8f79-286c8797419b.html
http://topic.csdn.net/u/20080107/21/a8a6fdd1-a434-4d11-a04f-fe54a424d8a4.html
线程调用WNetAddConnection2,但是这个函数只有同步工作的,而且可能会长时间不返回(我测试过一个无效的网络名,需要6秒多),那么有什么办法让它提前超时返回或者结束掉线程.大家可能第一反应是使用TerminateThread,但是这个API连栈也不释放,也就是说,连续2000次左右就没办法才创建线程了(稍微设置一下最多4000次),很明显,这是一个十分烂的方法.那么用进程去调用呢?进程创建太慢了.这似乎没什么好的办法去解决.

但是我已经在回帖里提出了解决方案,后来发现许多人也为阻塞或者休眠的线程而烦恼,大家在csdn里面搜索唤醒 阻塞 休眠 线程..我就封装成一个DLL--KexLib,给大家使用.

核心只有一个API,那就是:
int InvokeThread(DWORD dwTid,INVOKEPROC proc,DWORD par1,DWORD par2,DWORD par3);
参数分别是:
dwTid--目标线程id,可是是别的进程的线程
proc--线程回调函数
par1,par2,par3--回调函数的三个参数

proc示例如下:
void test1(DWORD dw1,DWORD dw2,DWORD dw3)
{
printf("%d %d %d %d timeout ~~~Exit\n",GetCurrentThreadId(),dw1,dw2,dw3);
ExitThread(0);
}

返回0表示成功

只要向目标线程调用此函数,那么正在休眠或者阻塞的线程就立刻被唤醒执行回调函数!
如果我们在回调函数中调用ExitThread就可以退出线程了.也就是达到了我们唤醒阻塞线程或者退出线程的目的了.

可能有人会说,那么申请的内存,对象也不会释放啊!确实如此,ExitThread只能回首栈空间,线程发出的挂起了的IRP,通知相关的DLL.而内存这些不是线程相关性的,所以不会被回收,但是这已经足够了.从任务管理器反馈的数据足已表明没有资源泄露.(如果线程使用beginthread创建的,那么使用_endthread,如果是AfxBeginhread创建的,使用AfxEndThread退出线程)

下面是示例代码:
该代码的主要流程:创建一线程,这个线程调用WNetAddConnection2执行任务,如果超过200ms没返回,那么主线程就调用InvokeThread,迫使工作线程退出.


//线程回调函数
void test1(DWORD dw1,DWORD dw2,DWORD dw3)
{
printf("%d %d %d %d timeout ~~~Exit\n",GetCurrentThreadId(),dw1,dw2,dw3);
ExitThread(0);
}

//线程函数
DWORD __stdcall ThreadFuncConnect(
void* lpRemoteName
){
DWORD dwFlags = CONNECT_INTERACTIVE;
NETRESOURCE nt;

char buf[] = "\\\\products2\\relsys";

ZeroMemory(&nt, sizeof(nt));
nt.lpLocalName = NULL;
nt.lpRemoteName = (LPTSTR)buf;
nt.dwType = RESOURCETYPE_ANY;
nt.lpProvider = NULL;

DWORD dw = GetTickCount();

DWORD dwErr = WNetAddConnection2(&nt, "", "administrator", dwFlags);

printf("connect end~~ time:%d\n",GetTickCount()-dw);

return 0;
}



int main(int argc, char* argv[])
{

ShowAbout();

BOOL bRet = FALSE;
bRet = InitKexLib();//初始化KexLib

DWORD dwTID;
HANDLE hThread;

while (1)
{
//创建一线程
hThread = CreateThread(NULL,0,ThreadFuncConnect,NULL,0,&dwTID);

if(hThread)
printf("%d create\n",dwTID);
else printf("err! %d\n",GetLastError());


CloseHandle(hThread);
Sleep(200);//如果该线程超过200ms没退出,则强制它退出
int i = InvokeThread(dwTID,test1,1,2,3);
}

bRet = ExitKexLib();//卸载KexLib

_getch();

return 0;
}

程序运行的时候,会频繁显示出超时退出,打开任务管理器观察,进程的内存,句柄计数,核心内存的分页数,未分页数,句柄总数.会发现没什么增减的,我测试过两小时.都正常.(应该在一个稳定的环境下运行测试程序,避免其他程序干扰)也就是,我们用ExitThread退出WNetAddConnection2阻塞的线程是安全可靠的.事实上WNetAddConnection2会向驱动发出IO请求,来完成网络资源的连接.而发出的挂起的IO请求在ExitThread的时候被释放.

当然我们也可以不退出线程,唤醒线程去完成别的任务也是可以的.同样也可以用于被Sleep等阻塞的线程上.

InvokeThread还可以杀进程,360,IceSword等可以轻松杀掉.先查找出他们的其中一个线程,然后按照下面的方式调用即可.
1268为他们的其中一个的线程ID.
InvokeThread(1268,(INVOKEPROC)GetProcAddress(LoadLibrary("ntdll"),"RtlFillMemory"),0x2000,0,10000);

另外KexLib还有几个API可以使用的.
//快速关机
extern "C" KEXLIB_API BOOL FastShutDown();

//快速重新启动
extern "C" KEXLIB_API BOOL FastReStart();

//复制文件,可以复制被锁定的文件,例如windows\system32\config\sam
extern "C" KEXLIB_API void RawCopyFile(LPCTSTR lpSrcName,LPCTSTR lpDstName);

//显示信息
extern "C" KEXLIB_API void ShowAbout();


本人是提倡share source , share idea的,但是上次在csdn上发布代码却遭来非议,所以本次不提供代码了,只提供测试代码.如果你想知道我用的是什么原理,用depends看看KexDrv.sys或者逆向之,不过10行代码,非常简单.
KexLib所包含的文件:
KexDrv.sys--驱动程序
KexLib.dll--接口DLL
KexLib.h--开发所需的头文件,接口函数都声明在这个头文件里面
KexLib.lib--开发所需的lib文件

请把sys和dll放在同一目录,另外我只测试了2000 sp4,xp sp2两个平台,所以此库只作测试用,出事不负责.


代码下载
http://download.csdn.net/source/473871

有什么疑问,请跟贴..发短消息不知道为什么我经常收不到..
...全文
610 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
renchhao 2009-05-26
  • 打赏
  • 举报
回复
如何copy啊 给我个程序就行 。。。。。185656156 QQ
siLence_Again 2008-09-30
  • 打赏
  • 举报
回复
不过话有说回来 suspend也是被阻塞了 呵呵~
siLence_Again 2008-09-30
  • 打赏
  • 举报
回复
拿notepad看了下 还是InsertApc呀?

挂死在内核态的线程根本就不会执行apc的呀?

suspend的线程也一样(直到被resume之时)
fgwxybmt 2008-07-09
  • 打赏
  • 举报
回复
有的时候会锁住,不知道为什么。
fgwxybmt 2008-06-11
  • 打赏
  • 举报
回复
我被阻塞问题困扰很久了,感激一下楼主,去实验喽~~
僵哥 2008-06-02
  • 打赏
  • 举报
回复
好贴,好东西,收下
明湖居士2018 2008-06-02
  • 打赏
  • 举报
回复
呵呵,牛人啊。
jameshooo 2008-05-30
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 KeSummer 的回复:]
哎..都是牛人...我一直徘徊在一颗星..
[/Quote]
这里没有适合你的板块,应该加一个“内核/驱动”板块。
greatws 2008-05-30
  • 打赏
  • 举报
回复
不错,顶一下
一条晚起的虫 2008-05-30
  • 打赏
  • 举报
回复
mark
heqiangfly 2008-05-29
  • 打赏
  • 举报
回复
学习
up
KeSummer 2008-05-29
  • 打赏
  • 举报
回复
哎..都是牛人...我一直徘徊在一颗星..
jameshooo 2008-05-29
  • 打赏
  • 举报
回复
我不算快,这里有个超级快的家伙:cnzdgs
KeSummer 2008-05-29
  • 打赏
  • 举报
回复
jameshooo升得真快..恭喜三星了。呵呵~~
jameshooo 2008-05-29
  • 打赏
  • 举报
回复
顶一下
KeSummer 2008-05-29
  • 打赏
  • 举报
回复
沙发自己坐~~

1,649

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 非技术类
社区管理员
  • 非技术类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧