我是否需要锁定来保护我的代码中的多线程竞争条件

do I need lock to protect mutli-thread race condition in my code

在 Windows 上使用 Python 2.7,并将使用支持真正多线程的 Jython。方法 sendMessage 用于接收来自特定客户端的消息,客户端可能会向其他几个客户端发送相同的消息(这就是参数 receivers 的用途,而 receivers一个列表)。方法 receiveMessage 用于接收来自其他客户端发送给特定客户端的消息。

问题是我是否需要方法 sendMessagereceiveMessage 的任何锁?我认为没有必要,因为即使客户端 X 正在接收其消息,另一个客户端 Y 附加到消息池以将消息传递给客户端 X 也是完美的。我认为 defaultdict/list,append/pop都是原子的,不需要保护。

如有错误欢迎指正

from collections import defaultdict

class Foo:
    def __init__(self):
        # key: receiver client ID, value: message
        self.messagePool = defaultdict(list)
    def sendMessage(self, receivers, message):
        # check valid for receivers
        for r in receivers:
            self.messagePool[r].append(message)
    def receiveMessage(self, clientID):
        result = []
        while len(self.messagePool[clientID]) > 0:
            result.append(self.messagePool[clientID].pop(0))

        return result

竞争条件是指两个或多个线程同时更改某些全局状态。

sendMessage 的代码中,您正在更改 self.messagePool[r],这是一个全局对象。因此,self.messagePool[r] 应该在附加新项目之前锁定。

与您的 receiveMessage 函数相同。

list.appendlist.pop 是自动化的 O(1) 和 O(1) 操作,因此它很少会导致任何竞争条件。但是,风险还是有的。

我建议使用 Queue 而不是 list。它是为 append\pop 带锁的线程设计的。

我认为这个问题已经在 CPython here and here (basically, you're safe because of GIL, although nothing in documentation (like on defaultdict or list) officially says about that). But I understand your concern about Jython, so let's solve it using some official source, like Jython source code. A pythonic list is a javaish PyList 中用这种代码得到了很好的回答:

public void append(PyObject o) {
    list_append(o);
}
final synchronized void list_append(PyObject o) {
...
}
public PyObject pop(int n) {
    return list_pop(n);
}
final synchronized PyObject list_pop(int n) {
...
}

并且因为我们有这些方法 synchronized,所以我们可以确定列表追加和弹出对于 Jython 也是线程安全的。因此,您的代码在线程处理方面似乎是安全的。

虽然 Queue 建议仍然有效,但它确实更适合这个用例。