views:

133

answers:

6

Dear C# geeks,

I have object obj which is 3rd party component,

// this could take more than 30 seconds
int result = obj.PerformInitTransaction(); 

I don't know what is happening inside. What I know is if it take longer time, it is failed.

how to setup a timeout mechanism to this operation, so that if it takes more than 30 seconds I just throw MoreThan30SecondsException ?

+10  A: 

You could run the operation in a separate thread and then put a timeout on the thread join operation:

using System.Threading;

class Program {
    static void DoSomething() {
        try {
            // your call here...
            obj.PerformInitTransaction();         
        } catch (ThreadAbortException) {
            // cleanup code, if needed...
        }
    }

    public static void Main(params string[] args) {

        Thread t = new Thread(DoSomething);
        t.Start();
        if (!t.Join(TimeSpan.FromSeconds(30))) {
            t.Abort();
            throw new Exception("More than 30 secs.");
        }
    }
}
Paolo Tedesco
+1  A: 

You might look at invoking the method in a thread and upon the timeout, abort the thread and raise the exception. Also, you shall have to handle the ThreadBorted Exception in this case.

Kangkan
You are right about the ThreadAbortedException, +1.
Paolo Tedesco
A: 

There is a nice example of a generic solution to this using a helper class here.

It uses the Action delegate to avoid the Thread creation/destruction shown in the previous example.

I hope this helps.

BrianB
+1  A: 

You need to be careful about aborting an operation like this, especially as it's in a 3rd party component that you (possibly) don't have access to the code to modify.

If you abort the operation then you won't know what state you've left the underlying class in. For example, it may have acquired a lock, and your about has caused that lock to not be released. Even if you destroy the object after aborting the operation it may have altered some state that is global to it and therefore you won't be able to reliably create a new instance without a restart.

Sean
+1  A: 

If you don't want to block the main thread you can use a System.Threading.Timer:

private Thread _thread;

void Main(string[] args)
{
    _thread = new ThreadStart(ThreadEntry);
    _thread.Start();
    Timer timer = new Timer(Timeout,null,30000,Timeout.Infinite);
}


void ThreadEntry()
{
    int result = obj.PerformInitTransaction(); 
}

void TimeOut(object state)
{
    // Abort the thread - see the comments
    _thread.Abort();

    throw new ItTimedOutException();
}

Jon Skeet has a less forceful way (Shutting Down Worker Threads Gracefully) of stopping the thread than abort.

However as you're not in control of the operations PerformInitTransaction() is doing there is not much you can do from when Abort fails and leaves the object in an invalid state. As mentioned if you are able to cleanup anything that aborting the PerformInitTransaction has left hanging, you can do this by catching the ThreadAbortException, though as it's a 3rd party call it'll mean guessing the state you've left their method in.

The PerformInitTransaction should really be the one providing the timeout.

Chris S
A: 

CodeProject has an interesting article on the subject.

Appu