views:

2795

answers:

8

I need to call a library function that sometimes won't terminate within a given time, unfortunately. Is there a way to call the function but abort it if it doesn't terminate within n seconds?

I cannot modify the function, so I cannot put the abort condition into it directly. I have to add a timeout to the function externally.

Is it maybe a possible solution to start it as a (boost) thread, which I can then terminate after a certain time? Would something like that work? I actually believe the function is not thread-safe, but that wouldn't matter if I run it as the only single thread, right? Are there other (better) solutions?

+6  A: 

What you are talking about is typically called a "watchdog" system. The watchdog is typically a second thread which checks on the status of all the other threads. The watchdog typically is setup to run periodically. If no response has been received from the other threads, the watchdog can notify the user, or even kill the offending thread if its possible to do so safely (depends on your application).

Doug T.
Depending on what the library function is doing, killing the unresponsive thread could be very unsafe. A safe approach would be to dispatch the task to a separate process.
Andrew
How do I start such a separate process? Can my application pass it some data (and get some result data back) without going through the file system?
That's somewhat complicated, and platform-specific - could easily be a separate stackoverflow question, I think. There are several ways to pass data between processes. This is called IPC (Inter-Process Communication) and is also platform-specific.
Andrew
+3  A: 

The problem with threads is that some resources you won't be able to free after thread termination. If you don't acquire resources which you have to release then go with threads.

Mykola Golubyev
Note that there are resources that could be acquired not under your control either - you could call API's that acquire locks and so on, and terminating the thread will result in orphaning those locks.
Michael
+12  A: 

I think the only safe way to accomplish this would be to spawn a separate sandbox process that calls the library function as a proxy to your application. You'll need to implement some type of IPC between your application and the proxy. Implementing a timeout on reading the IPC reply is then fairly trivial. If the read fails due to timeout, you can then safely terminate the proxy without risking the health of your application.

Andrew
+9  A: 

You could spawn a boost::thread to call the API:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}

Boost doesn't allow you to kill the worker thread, though. In this example, it's just orphaned.

You'll have to be careful about what that API call does, because it may never release resources it's acquired.

Ben Straub
If api_function returns a value, how can I access it?
Rupert Jones
This method creates a simple functor that calls the API directly. To capture the result, you'd have to write your own functor or lambda to assign the API's return code to some variable that can be accessed from elsewhere. In C++0x, you could write `RETTYPE retcode; boost::thread api_caller( [ });`
Ben Straub
+1  A: 

What you need is a thread and a Future Object that can hold the result from the function call.

For an example using boost see here.

You would need to check the future after the timeout and if it is not set, act accordingly.

lothar
Futures are cool and often useful, but I don't think they solve the problem the OP asked. He wants to **stop the function running** if it runs for too long.
j_random_hacker
Well he could try to terminate the thread if the timeout expires, but that is unsafe as many others have pointed out. If the function is terminating later (unless it's broken) then the future will allow him to continue his main program after the timeout and simply ignore the thread and the future knowing that it will sometime in the future terminate.
lothar
+2  A: 

Boost.Test's execution_monitor does what you want:

http://www.boost.org/doc/libs/1_39_0/libs/test/doc/html/execution-monitor/reference.html#boost.execution_monitor

Bruno Martinez
+1, interesting idea. I see that the timeout parameter does not work for Windows yet. Also, any resources used by the function are still going to be left in an indeterminate state (at least unallocated, and possibly in an invalid intermediate state), so don't try running your function more than once or depending on anything it touches.
j_random_hacker
+2  A: 

The problem is that with an in-process solution without support from the function you end up with potentially invalid state.

Example: When you terminate the thread while a memory allocation is taking place, your process heap may be corrupted.

So you might terminate the call, but then you also have to terminate the process. In many cases, the chances for destructive side effects are small, but I wouldn't bet my computation on that.

You can, as Ben Straub suggests, just orphan the thread: put it on lowest priority and let it run for infinity. That is of course only a limited solution: if the thread consumes ressources (likely), they will slow down the system, also there's a limit on threads per process (usually due to address space for thread stack).

Generally, I'd prefer the external process solution. A simple pattern is this:
Write input data to a file, start the external process with the file as argument. The external process writes progress (if any) to a disk file that can be monitored, and may even allow the process to resume from where it started. Results are written to disk, and the parent process can read them in.

When you terminate the process, you still have to deal with synchronizing access to external ressources (like files), and how to deal with abandoned mutices, half-written files etc. But it's generally THE way to a robust solution.

peterchen
A: 

Go with an Orphan process, launch it and time its execution. If it runs out of time, invoke the OS to kill it.

How to avoid race conds. on this pattern:

  • create a file to store in args (of course, everything is passed on as VALs). The orphan process is only allowed to read data from this file.

  • The orphan processes input data, creates an output file with result values and closes it.

  • Only when everything is done, orphan deletes the input file, a fact that signals the master process that work was done.

This avoids reading half-written files problem, since the master first notices absense of input file, opens for read the output file, which is surely completed (because was closed prior to deleting input, and OS call stacks are sequential).

jpinto3912