📜  信号量及其类型(1)

📅  最后修改于: 2023-12-03 15:22:28.252000             🧑  作者: Mango

信号量及其类型

信号量是一种线程同步机制,用于在多个线程之间协调共享资源的访问。它可以用于防止多个线程同时访问共享资源,以避免数据不一致的情况。

信号量是一个计数器,由一个整数表示,可以原子地增加或减少。当一个线程需要访问共享资源时,它会尝试获取信号量,如果信号量的值大于零,线程会将信号量的值减一并继续执行。如果信号量的值为零,线程将被阻塞,直到信号量的值大于零为止。当一个线程使用完共享资源后,它会将信号量的值加一表示释放资源。

在信号量的基础上,还有许多不同的类型,下面我们来介绍一下它们。

二元信号量

二元信号量,也称为互斥锁,只有两个可能的值:0和1。在多个线程中使用互斥锁时,只有一个线程可以访问共享资源,其他线程被阻塞。

在Python中,可以使用threading模块来创建和使用二元信号量。下面是一个例子:

import threading

lock = threading.Lock()

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

counter = 0

threads = []
for i in range(10):
    thread = threading.Thread(target=increment, args=(counter,))
    threads.append(thread)

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

print(counter) # 10

上面的代码创建了一个互斥锁,并在多个线程中使用它来保护对计数器变量的递增操作。由于互斥锁只允许一个线程访问共享资源,因此代码输出的结果应该是10。

计数信号量

计数信号量是一个整数值,它可以在多个线程之间共享。当一个线程访问共享资源时,它会将计数信号量的值减一。如果计数信号量的值为零,则线程将被阻塞,直到另一个线程将其加一。当一个线程完成访问共享资源时,它会将计数信号量的值加一。

在Python中,可以使用threading模块来创建和使用计数信号量。下面是一个例子:

import threading

sema = threading.Semaphore(3)

def access_resource(resource_id):
    with sema:
        # Access to shared resource
        pass

threads = []
for i in range(10):
    thread = threading.Thread(target=access_resource, args=(i,))
    threads.append(thread)

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

上面的代码创建了一个计数信号量,初始值为3。然后,它在多个线程中使用计数信号量来控制对共享资源的访问。由于计数信号量的值为3,因此只有三个线程可以同时访问共享资源。其他线程将被阻塞,直到其中一个线程完成访问。

Bounded Semaphore

Bounded Semaphore 是一种特殊的计数信号量,它有一个额外的上限值。当计数信号量的值达到上限时,任何尝试获取它的线程都会被阻塞。只有当信号量的值小于上限时,线程才可以成功获取它。

在Python中,可以使用multiprocessing模块来创建和使用Bounded Semaphore。下面是一个例子:

import multiprocessing

sema = multiprocessing.BoundedSemaphore(3)

def access_resource(resource_id):
    with sema:
        # Access to shared resource
        pass

processes = []
for i in range(10):
    process = multiprocessing.Process(target=access_resource, args=(i,))
    processes.append(process)

for process in processes:
    process.start()

for process in processes:
    process.join()

上述代码创建了一个Bounded Semaphore,初始值为3。然后,它在多个进程中使用Bounded Semaphore来控制对共享资源的访问。由于Bounded Semaphore的值为3,因此只有三个进程可以同时访问共享资源。其他进程将被阻塞,直到其中一个进程完成访问。

Condition

Condition是一种复杂的同步原语,它结合了锁和信号量的功能。线程可以使用Condition来等待另一个线程的通知,并在满足某个条件时执行操作。

在Python中,可以使用threading模块来创建和使用Condition。下面是一个例子:

import threading

cond = threading.Condition()

def worker_thread():
    with cond:
        cond.wait()
        # Do some work

def main_thread():
    with cond:
        cond.notify()

上述代码创建了一个Condition,并在一个线程中等待通知。在另一个线程中,我们可以使用notify方法通知运行需要执行操作的线程。

Event

Event是一种同步原语,它可用于多个线程之间的通信。一个线程可以等待某个事件的信号,并在触发事件时执行相应的操作。

在Python中,可以使用threading模块来创建和使用Event。下面是一个例子:

import threading

event = threading.Event()

def worker_thread():
    event.wait()
    # Do some work

def main_thread():
    event.set()

上面的代码创建了一个Event,并在一个线程中等待它的信号。在另一个线程中,我们可以使用set方法来触发事件,并允许等待线程执行操作。

Semaphore vs. Lock

Semaphore和Lock都是用于实现线程同步的机制。它们的主要区别在于,Semaphore允许多个线程同时访问共享资源,而Lock只允许一个线程访问共享资源。

当访问共享资源的顺序无关紧要时,应该使用Semaphore。当需要确保一次只有一个线程访问共享资源时,应该使用Lock。

下面是一个例子,展示了Semaphore和Lock的区别:

import threading

sema = threading.Semaphore(3)
lock = threading.Lock()

def access_resource_with_semaphore(resource_id):
    with sema:
        # Access to shared resource
        pass

def access_resource_with_lock(resource_id):
    with lock:
        # Access to shared resource
        pass

threads = []
for i in range(10):
    thread = threading.Thread(target=access_resource_with_semaphore, args=(i,))
    threads.append(thread)

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

print('Access with semaphore done.')

threads = []
for i in range(10):
    thread = threading.Thread(target=access_resource_with_lock, args=(i,))
    threads.append(thread)

for thread in threads:
    thread.start()

for thread in threads:
    thread.join()

print('Access with lock done.')

上述代码展示了如何使用Semaphore和Lock来访问共享资源。在第一个阶段中,我们创建了一个Semaphore并使用它来控制对共享资源的访问。在第二个阶段中,我们创建了一个Lock,并使用它来确保一次只有一个线程访问共享资源。通过观察输出结果,我们可以看到这两种机制的差异。

参考资料:

  • https://docs.python.org/3/library/threading.html
  • https://docs.python.org/3/library/multiprocessing.html
  • https://docs.python.org/3/library/threading.html#condition-objects
  • https://docs.python.org/3/library/threading.html#event-objects
  • https://stackoverflow.com/questions/21345245/what-are-the-differences-between-a-semaphore-and-a-lock