-1

I'm trying to create a generic method that accepts a delegate. The sole purpose of the method is to ensure whatever unique code block you pass to it, is only accessed by one thread at a time. I'm pointing out the word unique as unique code blocks can run side by side, duplicate code blocks must run synchronously. Is there a clean pattern to achieve this?

Captain Kirk
  • 350
  • 6
  • 24

2 Answers2

2

You can do something like this:

namespace RunSafe
{
    // Declare a delegate type
    public delegate void RunSafeDelegate();


    public class SafeRunner
    {
        private object _lock =  new Object();

        public void Runner( RunSafeDelegate runsafe )
        {
            lock( this._lock )
            {
                runsafe();
            }
        }
    }
}
Darrin Cullop
  • 1,170
  • 8
  • 14
  • Thanks Dex. Is there a way to enforce the lock only if the code block is the same? I essentially need this to scale so that if a different block of code is coming in, it should deal with that as a separate lock. – Captain Kirk Jun 22 '16 at 16:54
  • 1
    @user1701153 that's not a good way to do it. Code is immutable. It does not have to be protected. Locks protect data, not code. – usr Jun 22 '16 at 17:13
  • @usr Ultimately the code is acting on things that I need to protect. For example one code block I might be passing in would be to get a free tcp port. I want to synchronize that to avoid collisions. Etc. – Captain Kirk Jun 22 '16 at 18:19
  • That will only work if everybody uses the same instance of `SafeRunner`, and then you wouldn't be able to have more than one of them running at a time. – Jim Mischel Jun 22 '16 at 18:20
  • @JimMischel Agreed. Any suggestions on a better design? – Captain Kirk Jun 22 '16 at 18:32
  • Then you're synchronizing for ports, not the code. Create a lock or a "SafeRunner" controlling the port. – usr Jun 22 '16 at 18:55
  • @usr Thanks usr. I can definitely do that and know how to do that. My OP is really to see if I can simplify that kind of design to be more generic. Since I might have 20 things in the code that I need to synchronize i'd like to have a common lock utility that I can say hey, here's some unique code, make sure only one person runs it at a time. Instead of littering the code and putting that effort on other people. – Captain Kirk Jun 22 '16 at 19:14
0

Ultimately Dex Star's code example lead me down the path I was looking for.

If there are any concerns please let me know. I believe this is a solid solution. Note i'm using a named mutex on purpose as there may be multiple processes involved in accessing resources.

// test code
RunSafeDelegate rsd1 = () => { /* some code i need synchronous */ };
RunSafeDelegate rsd2 = () => { /* other code i need synchronous */ };

var util = new UtilityClass();
util.RunSafe(rsd1, "myMutexName1");
util.RunSafe(rsd2, "myMutexName2");

// implementation
public class UtilityClass
{
    public delegate void RunSafeDelegate();

    public void RunSafe(RunSafeDelegate runSafe, string mutexName)
    {
        const int WAIT_ONE_TIMEOUT = 30000;

        var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
        var mar = new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow);
        var ms  = new MutexSecurity();

        ms.AddAccessRule(mar);

        bool mutexCreated;

        using(var mutex = new Mutex(false, mutexName, out mutexCreated, ms))
        {
            var signalReceived = false;

            try
            {
                try
                {
                    signalReceived = mutex.WaitOne(WAIT_ONE_TIMEOUT, false);

                    if(!signalReceived)
                    {
                        throw new TimeoutException("Exclusive access timeout for mutex: " + mutexName);
                    }
                }
                catch(AbandonedMutexException)
                {
                    signalReceived = true;
                }

                runSafe();
            }
            finally
            {
                if(signalReceived)
                {
                    mutex.ReleaseMutex();
                }
            }
        }
    }
}
Captain Kirk
  • 350
  • 6
  • 24
  • I'm glad you got what you needed. If you are using Mutexes, they are IDisposable, so you'll want `using ( var mutex = new Mutex(false, mutexName) ) { }` ... Also, since your class no longer has instance members, you can make it, and its methods `static` and avoid having to instantiate it. – Darrin Cullop Jun 23 '16 at 15:44
  • @DexStar Thanks Dex. Greatly appreciate the advice. I've updated my implementation based on your feedback and some great information I found in another post: http://stackoverflow.com/questions/229565/what-is-a-good-pattern-for-using-a-global-mutex-in-c – Captain Kirk Jun 23 '16 at 16:37