Re: How to rollback another stack in C++?
Hi, Thanks very much. Let's dig a little bit more on this subject:
werasm wrote:
chengpu@gmail.com wrote:
Hi!
I am writing a thread-safe interface class <IThread> that exchange
messages in a multi-thread environment. Assume a thread is processing
a message in a function <IThread>::ProcMsg(), in two situations I need
to roll back this function's execution on another management thread:
(1) When it is in a infinitive loop. This can be detected by how much
time the function has been executing against a predefined timeout (say
10sec);
Does the thread have control over the code that is executed as result
of the message, or is this opaque. If it does not have control, the
possibility exists that the executed code is deliberately in an
infinite loop (like for example blocking on a select statement, or
Win32 I/O Completion Port). This type of thing would certainly appear
the same, from a higher level perspective, than an infinite loop.
If I was you I would not try and control (or prohibit) the possibility
of infinite loops, but trust the higher level to not deliberately cause
this. OTOH, I suppose a thread could have an attribute that indicates
that infinite loops are not allowed. In that case I would use the
concept of a Supervisoral thread to whom all threads report
periodically. On a thread not reporting, the Supervisoral Thread
terminates and respawns it, causing the stack to rewind automatically.
I am writing an interface base class <IThread>, and I do not have the
control of the implementation of the derived class. Your descriptions
fits into the infinitive loop: the derived <IThread>::ProcMsg() never
returns.
The normal implementation (Win32 and UNIX) of "terminates and respawns
it" has two
problems:
1) It never reclaim the stack, instead, it just abandons it, probably
creating a stack leak (but you never see this because you have a lot of
memory.
2) the state of the object is in limbo;
(2) When the sender of the message is dead, such as when a socket
connection is lost, there is no point to continue working on the
request from that connection;
As far as this is concerned, I think sometimes a request needs to be
executed despite the requester being dead, so to speak. It is more
important that the handler of the request still be available. I think
whether or not the request should be performed, could be an attribute
of the request itself. Something like:
struct RequestValidator
{
virtual bool isApplicable() const = 0;
};
struct Request
{
bool applicable() const
{
return( myValidator_ && myValidator()->isApplicable() );
}
//Called from receiving context
virtual void execute() = 0;
//...
};
//Receiving context/thread
void X::process()
{
Request* request( getNext() );
if( request.applicable() )
{
request.execute();
}
}
Note, I omitted allot of code, just to give you an idea. Hope it helps.
You mean for the <IThead>::ProcMsg() to poll isApplicable() between
each instruction? How about calling into other functions? I do not
think that this solution is elgant enough.
Anyway, the analog here is how to cancel a transaction.
In an embedded system, I can access the context switch handler, and I
can insert a generic exception pointer into my thread object. During
context switch, if the pointer is not 0, I can throw it when the
thread/stack becomes current.
Right now I do not think my rollback is possible in Win32 or UNIX, even
it is modest and reasonable. Because C++ or even OS does not provide
the rollback ability of a thread stack from outside, Java engine and
database engine essentially redo most OS calls to have this property.
Regards,
Chengpu
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]