19 个解决方案
#1
怎么样才算是优雅的退出呢?
#2
资源被正确回收,所有线程返回正确的值,个人有洁癖
#3
你这相当于强行终止,比如你正运行个多线程界面程序,然后把主进程在资源管理器给kill了,你还指望什么。
控制台程序运行完,自己就会退出。
#4
是这样的,服务端程序一般不会自动退出。我希望能有正常退出的方式来辅助我检测内存泄漏。
#5
SetConsoleCtrlHandler应该是可以的,你要在自己的HandlerRoutine中处理CTRL_CLOSE_EVENT信号。
#6
SetConsoleCtrlHandler应该是可以的,你要在自己的HandlerRoutine中处理CTRL_CLOSE_EVENT信号。
你试试就知道了,能捕捉到,但是返回值为2
#include "stdafx.h"
#include <Windows.h>
/*volatile*/ bool g_bExit = false;
BOOL CALLBACK CosonleHandler(DWORD ev)
{
BOOL bRet = FALSE;
switch (ev)
{
case CTRL_CLOSE_EVENT:
g_bExit = true;
bRet = TRUE;
break;
default:
break;
}
return bRet;
}
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
printf("exit\n");
system("pause");
return 0;
}
#7
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
#8
还可以从任务管理中终止呢。以前做过一个类似的,需要在内核中的进程列表中将其移除,这样用户就没有办法关闭这个程序。
#9
通过控制台窗口关闭按钮退出时,很多线程都没法正常退出,而且已构造的对象,都不会析构,即使用SetConsoleCtrlHandler去捕捉也一样。不知道有什么好的方法,我能想到的就是以监听键盘输入的方式来退出。
你这相当于强行终止,比如你正运行个多线程界面程序,然后把主进程在资源管理器给kill了,你还指望什么。
控制台程序运行完,自己就会退出。
是这样的,服务端程序一般不会自动退出。我希望能有正常退出的方式来辅助我检测内存泄漏。
如果真有这种需求,那改程序,增加个状态量(比如一个信号量,或者一个特定message(windows),程序再设计个观察者模式,主进程能有个机制接收用户输入一个特殊命令(或者捕获用户关闭的消息),然后把这个事件通知到每个线程,然后wait所有子线程退出后,自己再退出。
#10
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
这个方法可行
#11
不要企图优雅的结束(因为这是不可能办到的)
而要在烂的不能再烂的摊子上也能重整河山!
尽管如此:
console屏幕处理例子程序。终端窗口屏幕处理相关API使用例子。来自MSVC20\SAMPLES\win32\console\
http://download.csdn.net/detail/zhao4zhong1/3461309
而要在烂的不能再烂的摊子上也能重整河山!
尽管如此:
console屏幕处理例子程序。终端窗口屏幕处理相关API使用例子。来自MSVC20\SAMPLES\win32\console\
http://download.csdn.net/detail/zhao4zhong1/3461309
#12
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
#include <stdio.h>
#include <windows.h>
/*volatile*/ bool g_bExit = false;
BOOL CALLBACK CosonleHandler(DWORD ev)
{
BOOL bRet = FALSE;
switch (ev)
{
case CTRL_CLOSE_EVENT:
printf("exiting ...\n");
g_bExit = true;
bRet = TRUE;
break;
default:
break;
}
return bRet;
}
int main()
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
printf("exit\n");
system("pause");
return 0;
}
#13
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
你仔细看那个帖子的所有讨论,有讨论CTRL_CLOSE_EVENT,但实际效果并不理想。
把你代码稍加改动:
int main()
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
int i = 0;
while(TRUE)
{
printf("%d\n", i++);
}
printf("exit\n");
system("pause");
return 0;
}
可以看到printf只执行了可能一秒时间程序就退出了,并非MSDN上说的5秒。而且就算是5秒,也不能保证5秒之内一定能把所有处理完(PS:为什么MSDN上说是5秒,而实际是1秒,有知道的网友请@我告知
#14
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
13楼还没写完,就不小心按到回车了。
运行你12楼的代码,先打开任务管理器,定位到这个程序,然后单击右上角的X。此时,我们期望的是再按任意键程序退出,但在任务管理器中看到的实际情况却是单击了右上角X后1秒左右进程就消失了。
#15
崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。
#16
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
13楼还没写完,就不小心按到回车了。
运行你12楼的代码,先打开任务管理器,定位到这个程序,然后单击右上角的X。此时,我们期望的是再按任意键程序退出,但在任务管理器中看到的实际情况却是单击了右上角X后1秒左右进程就消失了。
我在12楼所说的是对7楼“好像无法捕获点击右上角X的事件”而言的,很明确CTRL_CLOSE_EVENT是可以响应关闭按钮点击事件的。
之所以改了一下你的代码,在case CTRL_CLOSE_EVENT:部分加了句printf("exiting ...\n");意思就是你在这加一句调用程序的退出处理过程就行了,至于CTRL_CLOSE_EVENT发出之后程序1秒结束还是5秒结束,应该不是大的问题,现代处理器上1秒可以执行数十亿条指令,你的程序起码也可以获得几十毫秒的时间片,除非要把大量数据写到文件,否则时间是足够的,线程不能及时终止应该是线程结构的问题,估计是在循环中有比较耗时的处理。
#17
之所以改了一下你的代码,在case CTRL_CLOSE_EVENT:部分加了句printf("exiting ...\n");意思就是你在这加一句调用程序的退出处理过程就行了,至于CTRL_CLOSE_EVENT发出之后程序1秒结束还是5秒结束,应该不是大的问题,现代处理器上1秒可以执行数十亿条指令,你的程序起码也可以获得几十毫秒的时间片,除非要把大量数据写到文件,否则时间是足够的,线程不能及时终止应该是线程结构的问题,估计是在循环中有比较耗时的处理。
这是对楼主说的。
#18
用了7楼的鼠标钩子,方法可行。不过有点小问题,也有时候捕捉不到,大概有10%的几率直接退出,没有捕获到关闭消息。
static HHOOK g_hHook;
static bool g_bExit = false;
/////////////////////////////////////////////////////////////////
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PMSLLHOOKSTRUCT pMouseInfo = (PMSLLHOOKSTRUCT)lParam;
if(nCode>=0 && wParam == WM_LBUTTONDOWN)
{
if(::SendMessage(::GetConsoleWindow(), WM_NCHITTEST, 0, pMouseInfo->pt.x + (pMouseInfo->pt.y<<16)) == HTCLOSE)
{
PostThreadMessage(GetCurrentThreadId(), UM_CLOSE, 0 , 0);
return TRUE;
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
///////////
g_hHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, 0);
HANDLE hListenThread = (HANDLE)_beginthreadex(NULL, 0, ListenTask, &sock, 0, NULL);
MSG msg;
BOOL bRet;
while( bRet=::GetMessage(&msg, NULL, 0, 0) )
{
if (bRet == -1)
{
printf("GetMessage fail: errVal=%d]n", ::GetLastError());
system("pause");
break;
}
if( msg.message == UM_CLOSE
&& ::MessageBox(::GetConsoleWindow(), "Confirm exit yes or not", "CenterServer", MB_YESNO) == IDYES )
{
g_bExit = true;
break;
}
}
::WaitForSingleObject(hListenThread, INFINITE);
::shutdown(sock, SD_BOTH);
::closesocket(sock);
//CThread::Delete();
::WSACleanup();
UnhookWindowsHookEx(g_hHook);
return 0;
}
#19
这似乎是个疑难杂症啊,现在也在纠结这个问题,难道要让用户输入个退出命令,而不是叉掉?
#20
#1
怎么样才算是优雅的退出呢?
#2
资源被正确回收,所有线程返回正确的值,个人有洁癖
#3
通过控制台窗口关闭按钮退出时,很多线程都没法正常退出,而且已构造的对象,都不会析构,即使用SetConsoleCtrlHandler去捕捉也一样。不知道有什么好的方法,我能想到的就是以监听键盘输入的方式来退出。
你这相当于强行终止,比如你正运行个多线程界面程序,然后把主进程在资源管理器给kill了,你还指望什么。
控制台程序运行完,自己就会退出。
#4
通过控制台窗口关闭按钮退出时,很多线程都没法正常退出,而且已构造的对象,都不会析构,即使用SetConsoleCtrlHandler去捕捉也一样。不知道有什么好的方法,我能想到的就是以监听键盘输入的方式来退出。
你这相当于强行终止,比如你正运行个多线程界面程序,然后把主进程在资源管理器给kill了,你还指望什么。
控制台程序运行完,自己就会退出。
是这样的,服务端程序一般不会自动退出。我希望能有正常退出的方式来辅助我检测内存泄漏。
#5
SetConsoleCtrlHandler应该是可以的,你要在自己的HandlerRoutine中处理CTRL_CLOSE_EVENT信号。
#6
SetConsoleCtrlHandler应该是可以的,你要在自己的HandlerRoutine中处理CTRL_CLOSE_EVENT信号。
你试试就知道了,能捕捉到,但是返回值为2
#include "stdafx.h"
#include <Windows.h>
/*volatile*/ bool g_bExit = false;
BOOL CALLBACK CosonleHandler(DWORD ev)
{
BOOL bRet = FALSE;
switch (ev)
{
case CTRL_CLOSE_EVENT:
g_bExit = true;
bRet = TRUE;
break;
default:
break;
}
return bRet;
}
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
printf("exit\n");
system("pause");
return 0;
}
#7
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
#8
还可以从任务管理中终止呢。以前做过一个类似的,需要在内核中的进程列表中将其移除,这样用户就没有办法关闭这个程序。
#9
通过控制台窗口关闭按钮退出时,很多线程都没法正常退出,而且已构造的对象,都不会析构,即使用SetConsoleCtrlHandler去捕捉也一样。不知道有什么好的方法,我能想到的就是以监听键盘输入的方式来退出。
你这相当于强行终止,比如你正运行个多线程界面程序,然后把主进程在资源管理器给kill了,你还指望什么。
控制台程序运行完,自己就会退出。
是这样的,服务端程序一般不会自动退出。我希望能有正常退出的方式来辅助我检测内存泄漏。
如果真有这种需求,那改程序,增加个状态量(比如一个信号量,或者一个特定message(windows),程序再设计个观察者模式,主进程能有个机制接收用户输入一个特殊命令(或者捕获用户关闭的消息),然后把这个事件通知到每个线程,然后wait所有子线程退出后,自己再退出。
#10
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
这个方法可行
#11
不要企图优雅的结束(因为这是不可能办到的)
而要在烂的不能再烂的摊子上也能重整河山!
尽管如此:
console屏幕处理例子程序。终端窗口屏幕处理相关API使用例子。来自MSVC20\SAMPLES\win32\console\
http://download.csdn.net/detail/zhao4zhong1/3461309
而要在烂的不能再烂的摊子上也能重整河山!
尽管如此:
console屏幕处理例子程序。终端窗口屏幕处理相关API使用例子。来自MSVC20\SAMPLES\win32\console\
http://download.csdn.net/detail/zhao4zhong1/3461309
#12
看看这个帖子:
控制台多线程安全退出
SetConsoleCtrlHandler可以捕获CTRL+C的事件,但好像无法捕获点击右上角X的事件。
我在8楼帖的代码,HOOK点击右上角X的鼠标消息,然后进行判断处理,只判断了点击右上角X的鼠标消息,没有捕获双击左上角关闭的鼠标消息。
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
#include <stdio.h>
#include <windows.h>
/*volatile*/ bool g_bExit = false;
BOOL CALLBACK CosonleHandler(DWORD ev)
{
BOOL bRet = FALSE;
switch (ev)
{
case CTRL_CLOSE_EVENT:
printf("exiting ...\n");
g_bExit = true;
bRet = TRUE;
break;
default:
break;
}
return bRet;
}
int main()
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
printf("exit\n");
system("pause");
return 0;
}
#13
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
你仔细看那个帖子的所有讨论,有讨论CTRL_CLOSE_EVENT,但实际效果并不理想。
把你代码稍加改动:
int main()
{
SetConsoleCtrlHandler(CosonleHandler, TRUE);
while(!g_bExit);
int i = 0;
while(TRUE)
{
printf("%d\n", i++);
}
printf("exit\n");
system("pause");
return 0;
}
可以看到printf只执行了可能一秒时间程序就退出了,并非MSDN上说的5秒。而且就算是5秒,也不能保证5秒之内一定能把所有处理完(PS:为什么MSDN上说是5秒,而实际是1秒,有知道的网友请@我告知
#14
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
13楼还没写完,就不小心按到回车了。
运行你12楼的代码,先打开任务管理器,定位到这个程序,然后单击右上角的X。此时,我们期望的是再按任意键程序退出,但在任务管理器中看到的实际情况却是单击了右上角X后1秒左右进程就消失了。
#15
崩溃的时候在弹出的对话框按相应按钮进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码或汇编指令处。
#16
CTRL_CLOSE_EVENT就是提供给用户程序处理关闭事件的,不管是system菜单的“close”(ALT+F4)还是右上角的关闭按钮,都会触发CTRL_CLOSE_EVENT。楼主的代码稍加修改:
...
13楼还没写完,就不小心按到回车了。
运行你12楼的代码,先打开任务管理器,定位到这个程序,然后单击右上角的X。此时,我们期望的是再按任意键程序退出,但在任务管理器中看到的实际情况却是单击了右上角X后1秒左右进程就消失了。
我在12楼所说的是对7楼“好像无法捕获点击右上角X的事件”而言的,很明确CTRL_CLOSE_EVENT是可以响应关闭按钮点击事件的。
之所以改了一下你的代码,在case CTRL_CLOSE_EVENT:部分加了句printf("exiting ...\n");意思就是你在这加一句调用程序的退出处理过程就行了,至于CTRL_CLOSE_EVENT发出之后程序1秒结束还是5秒结束,应该不是大的问题,现代处理器上1秒可以执行数十亿条指令,你的程序起码也可以获得几十毫秒的时间片,除非要把大量数据写到文件,否则时间是足够的,线程不能及时终止应该是线程结构的问题,估计是在循环中有比较耗时的处理。
#17
之所以改了一下你的代码,在case CTRL_CLOSE_EVENT:部分加了句printf("exiting ...\n");意思就是你在这加一句调用程序的退出处理过程就行了,至于CTRL_CLOSE_EVENT发出之后程序1秒结束还是5秒结束,应该不是大的问题,现代处理器上1秒可以执行数十亿条指令,你的程序起码也可以获得几十毫秒的时间片,除非要把大量数据写到文件,否则时间是足够的,线程不能及时终止应该是线程结构的问题,估计是在循环中有比较耗时的处理。
这是对楼主说的。
#18
用了7楼的鼠标钩子,方法可行。不过有点小问题,也有时候捕捉不到,大概有10%的几率直接退出,没有捕获到关闭消息。
static HHOOK g_hHook;
static bool g_bExit = false;
/////////////////////////////////////////////////////////////////
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PMSLLHOOKSTRUCT pMouseInfo = (PMSLLHOOKSTRUCT)lParam;
if(nCode>=0 && wParam == WM_LBUTTONDOWN)
{
if(::SendMessage(::GetConsoleWindow(), WM_NCHITTEST, 0, pMouseInfo->pt.x + (pMouseInfo->pt.y<<16)) == HTCLOSE)
{
PostThreadMessage(GetCurrentThreadId(), UM_CLOSE, 0 , 0);
return TRUE;
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
int main(int argc, char* argv[])
{
///////////
g_hHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, 0);
HANDLE hListenThread = (HANDLE)_beginthreadex(NULL, 0, ListenTask, &sock, 0, NULL);
MSG msg;
BOOL bRet;
while( bRet=::GetMessage(&msg, NULL, 0, 0) )
{
if (bRet == -1)
{
printf("GetMessage fail: errVal=%d]n", ::GetLastError());
system("pause");
break;
}
if( msg.message == UM_CLOSE
&& ::MessageBox(::GetConsoleWindow(), "Confirm exit yes or not", "CenterServer", MB_YESNO) == IDYES )
{
g_bExit = true;
break;
}
}
::WaitForSingleObject(hListenThread, INFINITE);
::shutdown(sock, SD_BOTH);
::closesocket(sock);
//CThread::Delete();
::WSACleanup();
UnhookWindowsHookEx(g_hHook);
return 0;
}
#19
这似乎是个疑难杂症啊,现在也在纠结这个问题,难道要让用户输入个退出命令,而不是叉掉?