Search code examples
.net-2.0consolelockingatomicconsole.setout

How can I ensure atomicity of a get-and-set operation to redirect Console.Out for logging console output?


I need to intercept the console output stream(s) in order to capture it for a log but still pass things through to the original stream so the application works properly. This obviously means storing the original Console.Out TextWriter before changing it with Console.SetOut(new MyTextWriterClass(originalOut)).

I assume the individual operations to get the Out property and to call the SetOut() method are implemented by Console in a thread-safe manner. But I'd like to make sure that some other thread (eg. running client application code that I don't control and can't expect to change, and so I can't rely on my own custom locking scheme) can't accidentally change it in between my get and set and end up getting overwritten by my change to it (breaking their application's behavior!). Since the other code may simply call SetOut(), my code should ideally get the same lock used internally by Console (assuming there is one).

Unfortunately, Console is a (static) class, not an instance, so you can't just lock (Console). And looking in the class documentation there does not seem to be any mention of locking. This is not the normally-expected usage of these Console methods, but there should be some safe way of doing this as an atomic operation.

Failing a standard locking scheme, is there some other way to ensure this? For such a short critical section (and done only once), even momentarily blocking all other threads might be acceptable, if that's the only way to do it. We're using C# and .NET2.0.

If not even that is possible (without disrupting the client application), then we'll just have to rely on it being very unlikely that the client application would redirect its console output and happen to do it in between our get and set operations. I'd just like to cover all the bases, just in case.

Edit: Now that we have a concrete answer with example code, I've reworded the question title to more generally reflect the use cases where the answer(s) can help, to be more clear. Also, added a tag for "atomic".


Solution

  • If you look at the implementation for SetOut it looks thread safe to me:

    [HostProtection(SecurityAction.LinkDemand, UI=true)]
    public static void SetOut(TextWriter newOut)
    {
        if (newOut == null)
        {
            throw new ArgumentNullException("newOut");
        }
        new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
        _wasOutRedirected = true;
        newOut = TextWriter.Synchronized(newOut);
        lock (InternalSyncObject)
        {
            _out = newOut;
        }
    }
    

    Edit

    The cloest thing to a solution I could come up with is using reflection to get their InternalSyncObject and then lock on it.

    A word of caution, this is an extremly bad idea and should only be used when no other option exists. You could cause the framework to behave unexpectadly and crash the process.

    You will also need to pay attention to any service packs and major releases making sure the internal variable is still used. Since its internal there is no promise that it will be there in the next release. Write your code defensivley and try and degrade the user experience nicely should you not the object with reflection.

    Good luck:-)