Locking by string. Is this safe/sane?

前端 未结 9 1631
-上瘾入骨i
-上瘾入骨i 2020-12-14 01:33

I need to lock a section of code by string. Of course the following code is hideously unsafe:

lock(\"http://someurl\")
{
    //bla
}

So I\'

相关标签:
9条回答
  • 2020-12-14 01:54

    This is how I implemented this locking schema:

    public class KeyLocker<TKey>
    {
        private class KeyLock
        {
            public int Count;
        }
    
        private readonly Dictionary<TKey, KeyLock> keyLocks = new Dictionary<TKey, KeyLock>();
    
        public T ExecuteSynchronized<T>(TKey key, Func<TKey, T> function)
        {
            KeyLock keyLock =  null;
            try
            {              
                lock (keyLocks)
                {
                    if (!keyLocks.TryGetValue(key, out keyLock))
                    {
                        keyLock = new KeyLock();
                        keyLocks.Add(key, keyLock);
                    }
                    keyLock.Count++;
                }
                lock (keyLock)
                {
                    return function(key);
                }
            }
            finally
            {         
                lock (keyLocks)
                {
                    if (keyLock != null && --keyLock.Count == 0) keyLocks.Remove(key);
                }
            }
        }
    
        public void ExecuteSynchronized(TKey key, Action<TKey> action)
        {
            this.ExecuteSynchronized<bool>(key, k =>
            {
                action(k);
                return true;
            });
        }
    }
    

    And used like this:

    private locker = new KeyLocker<string>();
    ......
    
    void UseLocker()
    {
         locker.ExecuteSynchronized("some string", () => DoSomething());
    }
    
    0 讨论(0)
  • 2020-12-14 01:56

    Here is a very simple, elegant and correct solution for .NET 4 using ConcurrentDictionary adapted from this question.

    public static class StringLocker
    {
        private static readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();
    
        public static void DoAction(string s, Action action)
        {
            lock(_locks.GetOrAdd(s, new object()))
            {
                action();
            }
        }
    }
    

    You can use this like so:

    StringLocker.DoAction("http://someurl", () =>
    {
        ...
    });
    
    0 讨论(0)
  • 2020-12-14 01:57

    In most cases, when you think you need locks, you don't. Instead, try to use thread-safe data structure (e.g. Queue) which handles the locking for you.

    For example, in python:

    class RequestManager(Thread):
        def __init__(self):
            super().__init__()
            self.requests = Queue()
            self.cache = dict()
        def run(self):        
            while True:
                url, q = self.requests.get()
                if url not in self.cache:
                    self.cache[url] = urlopen(url).read()[:100]
                q.put(self.cache[url])
    
        # get() runs on MyThread's thread, not RequestManager's
        def get(self, url):
            q = Queue(1)
            self.requests.put((url, q))
            return q.get()
    
    class MyThread(Thread):
        def __init__(self):
            super().__init__()
        def run(self):
            while True:
                sleep(random())
                url = ['http://www.google.com/', 'http://www.yahoo.com', 'http://www.microsoft.com'][randrange(0, 3)]
                img = rm.get(url)
                print(img)
    
    0 讨论(0)
提交回复
热议问题