退出,信号和例外 [英] exit, signals and exceptions

查看:64
本文介绍了退出,信号和例外的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好。我把这个问题发布到了comp.lang.c ++,但是从我学到的东西和发布到comp.lang.c ++中我的意思是一点点b / b。为了更多的洞察力而进行了调整。

那么我该如何解决我的问题呢?我想要它,以便当用户按下
Ctrl-C或从任务管理器编辑任务(或UNIX中的kill命令)然后

系统应该正常关闭。这意味着它应该调用所有对象的

析构函数,这意味着释放动态内存,关闭
套接字,关闭文件句柄,关闭SQL连接等。


我的方法是使用std :: signal设置信号处理程序。如果信号

处理程序什么也不做,程序会在引发

信号的位置恢复执行(类似于基本的RESUME命令)。


所以我的一个想法是在信号处理程序中抛出异常,并且在将控制权返回到函数中信号为
$ b的点之后为
$ b引发,程序将检测异常并执行堆栈展开。

但我们不允许在信号函数中抛出异常。在我的

编译器上,Borland C ++ 6我收到消息:<< Project.exe因

消息应用程序定义的异常而出现故障。流程已停止。使用步骤或运行来继续
。 >>


我的另一个想法是在信号处理程序中调用std :: exit。但不幸的是,这个函数并没有破坏所有堆栈中的本地对象。


那么我们还能做些什么呢?这似乎是一个普遍的问题,我很确定

人们已经深思熟虑了。也许使用longjmp会有所帮助吗?


这是我目前的解决方案,这个特殊情况似乎适用于

所有套接字都关闭了,但没有动态内存可以释放,文件

句柄关闭等等。

int global_s = -1;


void closesockets(int sig)

{

if(global_s!= -1)

{

closesocket (global_s);

global_s = -1;

}

WSACleanup();

if(sig)退出(sig);

}


class CloseSockets

{

public:

CloseSockets(){WSADATA wsa; WSAStartup(MAKEWORD(1,1),& wsa); }

~CloseSockets(){closesockets(0); }

private:

CloseSockets(const CloseSockets&); //未实现

CloseSockets& operator =(const CloseSockets&); //未实现

};

void server()

{

CloseSockets _closesockets;


int s = socket(AF_INET,SOCK_STREAM,0);

if(s == -1)throw std :: runtime_error(" fail socket");


global_s = s;

信号(SIGINT,& closesockets);

信号(SIGTERM,& closesockets);

信号(SIGABRT,& closesockets);


char myname [256];

int m = gethostname(myname,sizeof (myname));


hostent * myhost = gethostbyname(myname);

if(!myhost)throw std :: runtime_error(" no host" );


//致电绑定

//来电聆听


while(true)

{

/ *致电接受创建新套接字* /


而(true)

{

/ *致电recv * /

}


//致电closesocket

}

}

[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[comp.lang.c ++。moderated。第一次海报:做到这一点! ]

Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit
from what I learned and posting to comp.lang.c++.moderated for more insight.

So how do I solve my problem? I want it so that when the user presses
Ctrl-C or eds the task from task manager (or the kill command in UNIX) then
the system should shutdown gracefully. This means it should call the
destructors of all objects, which means freeing dynamic memory, closing
sockets, closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If the signal
handler does nothing the program resumes execution at the point where the
signal was raised (kind of like the RESUME command in basic).

So one of my thoughts was to throw an exception in the signal handler, and
after returning control to the point in the function where the signal was
raised, the program would detect the exception and perform stack unwinding.
But we are not allowed to throw exceptions in signal functions. On my
compiler, Borland C++ 6 I get the message: << Project.exe faulted with
message "application-defined exception". Process Stopped. Use Step or Run to
continue. >>

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I''m sure
people have put much thought into it. Maybe some use of longjmp could help?

Here''s my current solution, which seems to work in this special case in that
all sockets are closed, but there is no dynamic memory to release, file
handles to close, etc.
int global_s = -1;

void closesockets(int sig)
{
if (global_s != -1)
{
closesocket(global_s);
global_s = -1;
}
WSACleanup();
if (sig) exit(sig);
}

class CloseSockets
{
public:
CloseSockets() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~CloseSockets() { closesockets(0); }
private:
CloseSockets(const CloseSockets&); // not implemented
CloseSockets& operator=(const CloseSockets&); // not implemented
};
void server()
{
CloseSockets _closesockets;

int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) throw std::runtime_error("fail socket");

global_s = s;
signal(SIGINT , &closesockets);
signal(SIGTERM, &closesockets);
signal(SIGABRT, &closesockets);

char myname[256];
int m = gethostname(myname, sizeof(myname));

hostent * myhost = gethostbyname(myname);
if (!myhost) throw std::runtime_error("no host");

// call to bind
// call to listen

while (true)
{
/* call to accept which creates a new socket */

while (true)
{
/* call to recv */
}

// call to closesocket
}
}
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

推荐答案

" Siemel Naran" <硅********* @ REMOVE.att.net>写道:
"Siemel Naran" <Si*********@REMOVE.att.net> writes:
我想要它,以便当用户按下Ctrl-C或从任务管理器(或UNIX中的kill命令)编辑任务时,系统应该
正常关机。这意味着它应该调用所有对象的析构函数,这意味着释放动态内存,关闭套接字,关闭文件句柄,关闭SQL连接等。

我的方法是使用std :: signal设置信号处理程序。如果信号处理程序什么也不做,那么程序会在信号被引发的位置恢复执行(有点像RESUME命令基本的那样)。

所以我的一个想法是在信号
处理程序中抛出一个异常,[...]但我们不允许在信号
函数中抛出异常。 [...]

我的另一个想法是在信号处理程序中调用std :: exit。但不幸的是,这个功能并没有破坏所有堆栈中的本地对象。

那么我们还能做些什么呢?这似乎是一个普遍的问题,我确信人们已经深思熟虑了。也许使用一下
longjmp会有帮助吗?
I want it so that when the user presses Ctrl-C or eds the task from
task manager (or the kill command in UNIX) then the system should
shutdown gracefully. This means it should call the destructors of
all objects, which means freeing dynamic memory, closing sockets,
closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If
the signal handler does nothing the program resumes execution at the
point where the signal was raised (kind of like the RESUME command
in basic).

So one of my thoughts was to throw an exception in the signal
handler, [...] But we are not allowed to throw exceptions in signal
functions. [...]

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I''m
sure people have put much thought into it. Maybe some use of
longjmp could help?




信号处理程序需要使用POSIX函数sigsetjmp()和

siglongjmp(而不是setjmp()和longjmp()。即便如此,本地实例的析构函数不会被称为
。混合longjmp()和RAAI是一个坏主意。


一个解决方案是让信号处理程序设置一个全局变量

(声明为volatile sig_atomic_t),并在长持续时间的所有循环中定期检查此变量

。如果设置了变量,则可以通过抛出异常或正常停止循环

来初始化shutdown

。这种方法的缺点是你必须在*每个*循环中执行它可能会挂起一段时间的
,例如套接字读取

循环;你不能将关闭实现限制为信号

handler。此外,您必须能够异步停止或指定

超时,以便在收到信号

时可能正在运行的第三方功能,因为您可能不会能够为其中包含的循环添加关闭检查




此外,一些Unix系统会自动重启中断的系统调用

如果信号处理程序返回。您可以使用sigaction()而不是signal()并清除SA_RESTART

标志来禁用此行为,以避免系统在重新启动的读取中挂起( )

在收到Ctrl-C时称之为处理。


-

,------- ------------ MarkusBjartveitKrüger---------------------。

''``br />
`电子邮件: ma*****@pvv.org WWW: http://www.pvv.org/~markusk/ ''

)---------------------------------------------- ---------------------(


[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[ comp.lang.c ++。版主。第一次海报:做这个!]



Signal handlers need to use the POSIX functions sigsetjmp() and
siglongjmp() instead of setjmp() and longjmp(). Even so, destructors
for local instances won''t be called. Mixing longjmp() and RAAI is
generally a bad idea.

One solution is to let the signal handler set a global variable
(declared as volatile sig_atomic_t), and check this variable regularly
inside all loops of long duration. If the variable is set, shutdown
can be initialized by throwing an exception or stopping the loop
normally. The disadvantage of this approach is that you have to do it
in *every* loop that might hang for some time, e.g. socket-reading
loops; you cannot restrict the shutdown implementation to the signal
handler. Also, you must be able to asynchronously stop or specify
timeouts for third-party functions that may be running when the signal
is received, since you probably won''t be able to add shutdown checks
to loops contained in them.

Also, some Unix systems automatically restart interrupted system calls
if the signal handler returns. You can disable this behaviour by
using sigaction() instead of signal() and clearing the SA_RESTART
flag, in order to avoid that the system hangs in a restarted read()
call it was processing when Ctrl-C was received.

--
,------------------- Markus Bjartveit Krüger ---------------------.
'' `
` E-mail: ma*****@pvv.org WWW: http://www.pvv.org/~markusk/ ''
)-------------------------------------------------------------------(

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Siemel Nar an写道:


< summary>


当我的程序收到来自环境的KILL信号时,我该怎么办? b $ b确保所有活着物体是否被正确破坏?


当信号到达时,输入我的处理函数。如果我没有
从处理程序中明确地退出程序,程序执行将会在中断的任何地方恢复
。我不能从处理器的

中抛出异常。


< / summary>


最常见的习语似乎是全局变量的设置,

然后在程序的关键点检查。当然,

这是非常痛苦的。另一种方法是在程序中分配每个资源

,以便允许从信号处理程序中显式释放

;例如,可能有自定义分配器

用于内存,工厂用于管理其他资源的对象。


[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[comp.lang.c ++。moderated。第一次海报:做到这一点! ]
Siemel Naran wrote:

<summary>

When my program receives a KILL signal from the environment, how do I
make sure all "live" objects are destructed properly?

When the signal arrives, my handler function is entered. If I don''t
exit the program explicitly from the handler, program execution will
resume wherever it was interrupted. I can''t throw an exception from
the handler.

</summary>

The most common idiom seems to be the setting of a global variable,
which is then checked at strategic points in your program. Of course,
this is royally painful. An alternative would be having every resource
in the program allocated in a way that would allow explicit deallocation
from the signal handler; for example, there could be custom allocators
for memory, and factories for objects managing other resources.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


" Siemel Naran" <硅********* @ REMOVE.att.net>在消息新闻中写道:< Sx ********************* @ bgtnsc04-news.ops.worldnet.att.net> ...
"Siemel Naran" <Si*********@REMOVE.att.net> wrote in message news:<Sx*********************@bgtnsc04-news.ops.worldnet.att.net>...
嗨。我把这个问题发布到了comp.lang.c ++,但是从我学到的内容和发布到comp.lang.c ++中稍微改了一下。为了更多的洞察力而进行了调整。

那么怎么做我解决了我的问题?我想要它,以便当用户按下Ctrl-C或从任务管理器编辑任务(或UNIX中的kill命令)时,系统应该正常关闭。这意味着它应该调用所有对象的析构函数,这意味着释放动态内存,关闭套接字,关闭文件句柄,关闭SQL连接等。

我的方法是使用std :: signal设置信号处理程序。如果信号
处理程序什么都不做,程序会在
信号被引发的位置恢复执行(有点像基本的RESUME命令)。

所以我的一个想法是在信号处理程序中抛出异常,并且在将控制权返回到函数中引发信号的点之后,程序将检测到异常并执行堆栈展开。
但是我们不允许在信号函数中抛出异常。在我的
编译器上,Borland C ++ 6我收到了消息:<< Project.exe出现
消息应用程序定义的异常。流程已停止。使用步骤或运行继续。 >>

我的另一个想法是在信号处理程序中调用std :: exit。但不幸的是,这个功能并没有破坏所有堆栈中的本地对象。

那么我们还能做些什么呢?这似乎是一个普遍的问题,我很确定人们已经深思熟虑了。也许使用longjmp会有所帮助吗?

这是我目前的解决方案,这似乎适用于这种特殊情况,即所有套接字都关闭,但没有动态内存发布,文件
句柄关闭等。

int global_s = -1;

void closesockets(int sig)
{
if(global_s!= -1)
{closes>(global_s);
global_s = -1;
}
WSACleanup();
if( sig)exit(sig);


类CloseSockets
公开:
CloseSockets(){WSADATA wsa; WSAStartup(MAKEWORD(1,1),& wsa); }
~CloseSockets(){closesockets(0);私有:
CloseSockets(const CloseSockets&); //未实现
CloseSockets& operator =(const CloseSockets&); //未实现
};

void server()
{
CloseSockets _closesockets;

int s = socket(AF_INET,SOCK_STREAM ,0);
if(s == -1)throw std :: runtime_error(" fail socket");

global_s = s;
signal(SIGINT,& ; closesockets);
信号(SIGTERM,& closesockets);
信号(SIGABRT,& closesockets);

char myname [256];
int m = gethostname(myname,sizeof(myname));

hostent * myhost = gethostbyname(myname);
if(!myhost)throw std :: runtime_error(" no host");

//致电绑定
//致电倾听

while(true)
{
/ *致电接受哪个创造一个新的插座* /

while(true)
{
/ *致电recv * /
}

//致电closesocket
}
}
Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit
from what I learned and posting to comp.lang.c++.moderated for more insight.

So how do I solve my problem? I want it so that when the user presses
Ctrl-C or eds the task from task manager (or the kill command in UNIX) then
the system should shutdown gracefully. This means it should call the
destructors of all objects, which means freeing dynamic memory, closing
sockets, closing file handles, close SQL connections, etc.

My approach was to set up a signal handler using std::signal. If the signal
handler does nothing the program resumes execution at the point where the
signal was raised (kind of like the RESUME command in basic).

So one of my thoughts was to throw an exception in the signal handler, and
after returning control to the point in the function where the signal was
raised, the program would detect the exception and perform stack unwinding.
But we are not allowed to throw exceptions in signal functions. On my
compiler, Borland C++ 6 I get the message: << Project.exe faulted with
message "application-defined exception". Process Stopped. Use Step or Run to
continue. >>

My other thought was to call std::exit in the signal handler. But
unfortunately this function not destroy local objects in all stacks.

So what else can we do? This seems to be a common problem, and I''m sure
people have put much thought into it. Maybe some use of longjmp could help?

Here''s my current solution, which seems to work in this special case in that
all sockets are closed, but there is no dynamic memory to release, file
handles to close, etc.
int global_s = -1;

void closesockets(int sig)
{
if (global_s != -1)
{
closesocket(global_s);
global_s = -1;
}
WSACleanup();
if (sig) exit(sig);
}

class CloseSockets
{
public:
CloseSockets() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~CloseSockets() { closesockets(0); }
private:
CloseSockets(const CloseSockets&); // not implemented
CloseSockets& operator=(const CloseSockets&); // not implemented
};
void server()
{
CloseSockets _closesockets;

int s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1) throw std::runtime_error("fail socket");

global_s = s;
signal(SIGINT , &closesockets);
signal(SIGTERM, &closesockets);
signal(SIGABRT, &closesockets);

char myname[256];
int m = gethostname(myname, sizeof(myname));

hostent * myhost = gethostbyname(myname);
if (!myhost) throw std::runtime_error("no host");

// call to bind
// call to listen

while (true)
{
/* call to accept which creates a new socket */

while (true)
{
/* call to recv */
}

// call to closesocket
}
}




也许我想念一些东西,但我做的没有看到需要

异常或需要退出()。


静态bool return_from_server = false;


externC void signalhandler(int){

return_from_server = true;

}


struct WSASystem {

WSASystem(){WSADATA wsa; WSAStartup(MAKEWORD(1,1),& wsa); } $ / $
~WSASystem(){WSACleanup(); }

};


类套接字{

const int x_;

public:

Socket(int x):x_(x){}

~Socket(){if(x_!= -1)closesocket(x_); }

int c_int()const {return x_; }

};


void server(){

const WSASystem wsa;


const Socket s(socket(AF_INET,SOCK_STREAM,0));

if(s.c_int()== -1){

/ * TODO:Give通知失败的套接字到一些适当的

信息频道或者直到来电者。

尽管socket()声称它是一个错误,对我们来说

的情况这很正常 - 我们预计它现在会发生

然后 - ,这不是错误也不是例外。 * /

返回;

}


std :: signal(SIGINT,& signalhandler);

std :: signal(SIGTERM,& signalhandler);

std :: signal(SIGABRT,& signalhandler);


char myname [ 256];

const int m(gethostname(myname,sizeof(myname)));


hostent * const myhost(gethostbyname(myname));

if(myhost == 0){

/ * TODO:发出通知没有主机到一些适当的

信息频道或者直到来电者。

这种情况​​很正常 - 我们预计会发生这种情况

偶尔 - ,这不是错误也不是例外。 * /

返回;

}


//致电绑定

//致电聆听


for(;;){

if(return_from_server){

return;

}

/ *调用accept来创建一个新的套接字* /


for(;;){

if(return_from_server) ){

返回;

}

/ *致电recv * /

}

}

}


当然它根本不完整(恢复

信号处理程序丢失,... 。)。


Volker


[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[comp.lang.c ++。主持。第一次海报:做到这一点! ]



Maybe I miss something, but I do not see the need for
exceptions or the need for exit().

static bool return_from_server = false;

extern "C" void signalhandler(int) {
return_from_server = true;
}

struct WSASystem {
WSASystem() { WSADATA wsa; WSAStartup(MAKEWORD(1, 1), &wsa); }
~WSASystem() { WSACleanup(); }
};

class Socket {
const int x_;
public:
Socket(int x) : x_(x) {}
~Socket() { if (x_ != -1) closesocket(x_); }
int c_int() const { return x_; }
};

void server() {
const WSASystem wsa;

const Socket s(socket(AF_INET, SOCK_STREAM, 0));
if (s.c_int() == -1) {
/* TODO: Give notice "fail socket" to some appropriate
information channel or up to the caller.
Although socket() claims it to be an error, for us the
situation is quite normal - we expect it to happen now
and then -, it is not an error nor an exception. */
return;
}

std::signal(SIGINT, &signalhandler);
std::signal(SIGTERM, &signalhandler);
std::signal(SIGABRT, &signalhandler);

char myname[256];
const int m(gethostname(myname, sizeof(myname)));

hostent* const myhost(gethostbyname(myname));
if (myhost == 0) {
/* TODO: Give notice "no host" to some appropriate
information channel or up to the caller.
This situation is quite normal - we expect it to happen
now and then -, it is not an error nor an exception. */
return;
}

// call to bind
// call to listen

for (;;) {
if (return_from_server) {
return;
}
/* call to accept which creates a new socket */

for (;;) {
if (return_from_server) {
return;
}
/* call to recv */
}
}
}

Of course it is not complete at all (restoration of
signal handlers missing, ...).

Volker

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


这篇关于退出,信号和例外的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆