获取锁定锁是否被锁定

时间:2018-08-21 07:14:14

标签: python python-3.x multithreading thread-safety race-condition

在Python 3中,我想获取一个锁,然后知道它是否被阻塞。问题在于,如果threading.Lock.acquireTrue调用,则总是返回blocking=True,因此无法得知调用该函数时该锁是否已经被锁定。以下面的代码为例:

import threading

foo = None
lock = threading.Lock()

def bar():
    global foo
    # Only compute foo in one thread at a time.
    if not lock.acquire(blocking=False):
        # The race condition exists here.
        # Another thread is already computing foo.
        # This instance does not need to recompute foo.
        # Wait for that instance to finish.
        with lock:
            # Just return the value that the other instance computed.
            return foo
    # No other instance of this function is computing foo.
    with lock:
        # Compute foo.
        foo = [something]
        return foo

这里的问题是,lock可以再次获得,其中上面代码中的注释指出存在竞争条件。

如果这是因为第三个线程在该函数中的同一点先继续并获得了锁,则这是不希望的,因为它会引入一些延迟。 return foo确实没有理由需要受到保护;两个线程应该能够同时执行此操作。

但是,如果获取是由于另一个线程重新计算foo导致的,那么这是不希望的,因为一旦释放锁,foo就会发生变化。该函数应返回在调用时正在计算的foo的值。如果foo发生变化,那么它将无法再返回该值。

理想情况下,我们将拥有一个acquire函数,该函数可以阻止并仍然返回是否阻止。这样,我们可以放心地断言该函数总是返回调用该函数时正在计算的foo的值,并且只有在尚未foo进行计算的情况下,该函数才会继续执行,计算它,并返回新值。可以用Python完成吗?

1 个答案:

答案 0 :(得分:2)

我知道这个问题很老了,但由于我在寻找其他问题时偶然发现了它并且没有答案,我想我会做任何找到它的服务并回答它的人。

您首先检查锁是否可用,从而导致了竞争条件。您应该尝试在不检查的情况下获取锁,如下所示:

public $const = [
    "aws_endpoint" => "https://ip:port",
    "aws_key" => "login",
    "aws_secret" => "***********",
    "aws_bucket" => "testbucket",
];

$s3 = Aws\S3\S3Client::factory([
            'version' => 'latest',
            'region' => 'eu-north-1',
            'endpoint' => $this->const["aws_endpoint"],
            'credentials' => [
                'key' => $this->const["aws_key"],
                'secret' => $this->const["aws_secret"],
            ],
        ]);
        return $s3->putObject([
            'Bucket' => $this->const["aws_bucket"],
            'Key' => $objectKey,
            'SourceFile' => $pathToFile,
            'ContentLength' => filesize($pathToFile),
            'ContentSHA256' => hash_file("sha256", $pathToFile),
        ]);