动态分配和销毁互斥锁​​?

时间:2011-03-22 11:37:00

标签: python multithreading locking

我有一个建立在Eventlet之上的应用程序。

我正在尝试编写一个体面的装饰器,用于跨线程同步对某些方法的调用。

装饰者目前看起来像这样:

_semaphores_semaphore = semaphore.Semaphore()
_semaphores = {}

def synchronized(name):
    def wrap(f):
        def inner(*args, **kwargs):
            # Grab the lock protecting _semaphores.
            with _semaphores_semaphore:
                # If the named semaphore does not yet exist, create it.
                if name not in _semaphores:
                    _semaphores[name] = semaphore.Semaphore()
                sem = _semaphores[name]

            with sem:
                return f(*args, **kwargs)

这个工作正常,看起来很好并且对我来说是线程安全的,虽然整个线程的安全和锁定业务对我来说可能有点生疏。

问题是应用程序中其他地方的信号量的特定的,现有的使用,我想要转换为使用这个装饰器,动态创建这些信号量:基于用户输入,它必须创建一个文件。它检查一个字典是否已经有这个文件的信号量,如果没有,它会创建一个,并锁定它。一旦完成并释放锁定,它会检查它是否已被锁定(同时由另一个进程锁定),如果没有,则删除信号量。这段代码是在假设绿色线程的情况下编写的,并且在该上下文中是安全的,但如果我想将其转换为使用我的装饰器,那么这就是我无法解决的问题。

如果我不关心清理可能永远不会再使用的信号量(可能有数十万个这样的信号量),我很好。如果我想清理它们,我不知道该怎么做。

要删除信号量,似乎很明显我需要持有_semaphores_semaphore,因为我正在操纵_semaphores dict,但我也必须对特定的信号量做一些事情,但我能想到的一切似乎都是好色吗  *在“with sem:”块中,我可以从_semaphores中获取_semaphores_semaphore和sem。但是,其他线程可能会被阻塞等待它(在“with sem:”处),如果一个新线程想要触摸相同的资源,它将不会在_semaphores中找到相同的信号量,而是创建一个新的= >失败。 我可以通过检查sem的余额来查看是否有其他线程已经在等待我释放它。如果是这样,请不要管它,如果没有,请将其删除。这样,等待对资源执行操作的最后一个线程将删除它。但是,如果一个线程刚刚离开了“with _semaphores_semaphore:”块,但还没有使用“sem:”,那么我遇到了与之前相同的问题=>失败。

感觉我错过了一些明显的东西,但我无法理解它是什么。

2 个答案:

答案 0 :(得分:0)

我认为你可以用读写器锁来解决它。 _semaphores字典上的共享独占锁。 这是未经测试的代码,以显示原理。可以在例如RWLock实现中找到RWLock实现。 http://code.activestate.com/recipes/413393-multiple-reader-one-writer-mrow-resource-locking/

_semaphores_rwlock = RWLock()
_semaphores = {}

def synchronized(name):
    def wrap(f):
        def inner(*args, **kwargs):
            lock = _semaphores_rwlock.reader()
            # If the named semaphore does not yet exist, create it.
            if name not in _semaphores:
                lock = _semaphores_rwlock.writer()
                _semaphores[name] = semaphore.Semaphore()

            sem = _semaphores[name]

            with sem:
                retval = f(*args, **kwargs)
            lock.release()
            return retval

当您要清理时,请执行以下操作:

wlock = _semaphores_rwlock.writer() #this might take a while; it waits for all readers to release
cleanup(_semaphores)
wlock.release()

答案 1 :(得分:0)

mchro的回答对我不起作用,因为只要一个线程需要创建一个新的信号量,它就会阻塞单个信号量上的所有线程。

我想出的答案是在_semaphores的两个交易之间保留占用者的计数器(这两个交易都在同一个互斥锁之后完成):

A: get semaphore
A1: dangerzone
B: with sem: block etc
C: cleanup semaphore

问题在于了解AC之间有多少人。信号量的计数器并没有告诉你,因为有人可能在A1。答案是在_semaphores中保持参与者的计数器和每个信号量,在A递增,在C递减,如果在0,那么你知道没有 - <{1}}中的其他人 - A使用相同的密钥,您可以安全地将其删除。