📜  OS Binary Semaphore或Mutex(1)

📅  最后修改于: 2023-12-03 14:44:58.225000             🧑  作者: Mango

OS Binary Semaphore或Mutex

在操作系统中,二元信号量(也称为互斥量)和互斥锁是用于协调并发访问共享资源的基本工具。它们允许线程或进程在访问共享资源时相互排斥,以避免竞争条件和死锁等问题。

二元信号量

二元信号量是一个计数器,只有两种值:0和1。当它的值为1时,表示资源可用,线程可以访问它。当它的值为0时,表示资源不可用,线程必须等待其他线程释放该资源。因为它只有两个值,所以又称为二元信号量或二元信号灯。

二元信号量通过两个操作来实现:

  • P操作(等待操作):如果计数器的值为0,则线程将被阻塞,否则计数器值将减1。
  • V操作(释放操作):将计数器的值加1,如果有线程因为等待该资源而被阻塞,它将被唤醒。

例如,下面是一个使用二元信号量实现的简单生产者-消费者模型:

from threading import Semaphore, Thread

semaphore = Semaphore(0)
buffer = None

def producer():
    global buffer
    # Produce item
    buffer = "Hello"
    # Signal consumer
    semaphore.release()

def consumer():
    global buffer
    # Wait for item
    semaphore.acquire()
    # Consume item
    print(buffer)

t1 = Thread(target=producer)
t2 = Thread(target=consumer)
t1.start()
t2.start()

在这个例子中,生产者线程通过设置buffer变量来生产一个项目,并使用semaphore.release()向消费者线程发出信号。消费者线程通过semaphore.acquire()等待信号,并在接收到信号后消费buffer中的项目。

互斥锁

互斥锁是另一种协调并发访问共享资源的工具。与二元信号量不同,互斥锁可以跟踪哪个线程目前持有锁,并保证只有一个线程可以持有锁。

互斥锁通过两个操作来实现:

  • lock.acquire():如果锁当前没有被持有,则线程获得锁并继续执行;否则线程会阻塞直到锁被释放。
  • lock.release():释放锁,并允许其他线程获取锁。

例如,下面是一个使用互斥锁实现的简单计数器:

from threading import Lock, Thread

counter = 0
lock = Lock()

def increment():
    global counter
    with lock:
        counter += 1

threads = []
for i in range(10):
    t = Thread(target=increment)
    threads.append(t)
    t.start()

for t in threads:
    t.join()

print(counter)

在这个例子中,多个线程并发访问计数器变量counter,但是由于使用了互斥锁lock,每次只有一个线程能够获得锁并增加计数器变量的值。最终输出的counter变量值应该是10。

总结一下,二元信号量和互斥锁都是操作系统中用于协调并发访问共享资源的基本工具。二元信号量只有两个值(0或1),它用于线程之间的独占或相互排斥。互斥锁则是一个可拥有的标记,它用于控制多个线程对共享资源的访问。决定使用哪个工具取决于具体情况需求。