views:

148

answers:

7

I have a C# app that needs to do a hot swap of a data input stream to a new handler class without breaking the data stream.

To do this, I have to perform multiple steps in a single thread without any other threads (most of all the data recieving thread) to run in between them due to CPU switching.

This is a simplified version of the situation but it should illustrate the problem.

void SwapInputHandler(Foo oldHandler, Foo newHandler)
{
    UnhookProtocol(oldHandler);
    HookProtocol(newHandler);
}

These two lines (unhook and hook) must execute in the same cpu slice to prevent any packets from getting through in case another thread executes in between them.

How can I make sure that these two commands run squentially using C# threading methods?

edit
There seems to be some confusion so I will try to be more specific. I didn't mean concurrently as in executing at the same time, just in the same cpu time slice so that no thread executes before these two complete. A lock is not what I'm looking for because that will only prevent THIS CODE from being executed again before the two commands run. I need to prevent ANY THREAD from running before these commands are done. Also, again I say this is a simplified version of my problem so don't try to solve my example, please answer the question.

+1  A: 

Your data receiving thread needs to lock around accessing the handler pointer and you need to lock around changing the handler pointer.

Alternatively if your handler is a single variable you could use Interlocked.Exchange() to swap the value atomically.

Aaron
This won't work, a lock around accessing the handler reference returns immediately, you need a shared lock between threads that locks around all logical operations with handlers that should be atomic (IE a read followed by a write)
Pop Catalin
@Pop while this is wise advice, we cannot know for certain since there are no implementation details given. It is enitrely possible to correctly use Interlocked.Exchange to achieve the desired effect.
James Dunne
A: 

Why not go at this from another direction, and let the thread in question handle the swap. Presumably, something wakes up when there's data to be handled, and passes it off to the current Foo. Could you post a notification to that thread that it needs to swap in a new handler the next time it wakes up? That would be much less fraught, I'd think.

Sixten Otto
This simple example is not indicitive of the entire problem, I'm just looking for a very specific answer to implement a part of my solution. I can't use your suggestion because of the way the rest of the app is structured.
CodeFusionMobile
+4  A: 

Performing the operation in a single time slice will not help at all - the operation could just execute on another core or processor in parallel and access the stream while you perform the swap. You will have to use locking to prevent everybody from accessing the stream while it is in an inconsistent state.

Daniel Brückner
A: 

Okay - to answer your specific question.

You can enumerate through all the threads in your process and call Thread.Suspend() on each one (except the active one), make the change and then call Thread.Resume().

Aaron
What if another thread is trying to do the same thing concurrently? Can anything terrible go wrong? Is there any scenario in which every thread ends up suspended?
Eric Lippert
Yes - if two threads are doing this they can kill each other. My initial recomendation was to use a lock but apparently the OP knows better...
Aaron
@Aaron if I knew better, I wouldn't be asking...
CodeFusionMobile
A: 

Assuming your handlers are thread safe, my recommendation is to write a public wrapper over your handlers that does all the locking it needs using a private lock so you can safely change the handlers behind the scenes.

If you do this you can also use a ReaderWriterLockSlim, for accessing the wrapped handlers which allows concurrent read access.

Or you could architect your wrapper class and handler clases in such a way that no locking is required and the handler swamping can be done using a simple interlocked write or compare exchange.

Here's and example:

public interface IHandler
{
    void Foo();
    void Bar();
}

public class ThreadSafeHandler : IHandler
{

    ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
    IHandler wrappedHandler;

    public ThreadSafeHandler(IHandler handler)
    {
        wrappedHandler = handler;
    }

    public void Foo()
    {
        try
        {
            rwLock.EnterReadLock();
            wrappedHandler.Foo();
        }
        finally
        {
            rwLock.ExitReadLock();
        }
    }

    public void Bar()
    {
        try
        {
            rwLock.EnterReadLock();
            wrappedHandler.Foo();
        }
        finally
        {
            rwLock.ExitReadLock();
        }
    }

    public void SwapHandler(IHandler newHandler)
    {
        try
        {
            rwLock.EnterWriteLock();
            UnhookProtocol(wrappedHandler);
            HookProtocol(newHandler);
        }
        finally
        {
            rwLock.ExitWriteLock();
        }
    }
}

Take note that this is still not thread safe if atomic operations are required on the handler's methods, then you would need to use higher order locking between treads or add methods on your wrapper class to support thread safe atomic operations (something like, BeginTreadSafeBlock() folowed by EndTreadSafeBlock() that lock the wrapped handler for writing for a series of operations.

Pop Catalin
A: 

You can't and it's logical that you can't. The best you can do is avoid any other thread from disrupting the state between those two actions (as have already been said).

Here is why you can't:

Imagine there was an block that told the operating system to never thread switch while you're on that block. That would be technically possible but will lead to starvation everywhere.

You might thing your threads are the only one being used but that's an unwise assumption. There's the garbage collector, there are the async operations that works with threadpool threads, an external reference, such as a COM object could span its own thread (in your memory space) so that noone could progress while you're at it.

Imagine you make a very long operation in your HookOperation method. It involves a lot of non leaky operations but, as the Garbage Collector can't take over to free your resources, you end up without any memory left. Or imagine you call a COM object that uses multithreading to handle your request... but it can't start the new threads (well it can start them but they never get to run) and then joins them waiting for them to finish before coming back... and therefore you join on yourself, never returning!!.

Jorge Córdoba
A: 

As other posters have already said, you can't enforce system-wide critical section from user-mode code. However, you don't need it to implement the hot swapping.

Here is how.

Implement a proxy with the same interface as your hot-swappable Foo object. The proxy shall call HookProtocol and never unhook (until your app is stopped). It shall contain a reference to the current Foo handler, which you can replace with a new instance when needed. The proxy shall direct the data it receives from hooked functions to the current handler. Also, it shall provide a method for atomic replacement of the current Foo handler instance (there is a number of ways to implement it, from simple mutex to lock-free).

atzz