服务器 第7.2章 进程和线程-同步方式 服务器 第7.2章 进程和线程-同步方式

10小时前

一、同步方式

进程和线程都可能需要同步,特别是在多线程或多进程环境下,防止多个执行单元(线程或进程)对共享资源的竞争和冲突。

以下是常见的同步方式,以及哪些可以用在线程中,哪些可以用在进程中而不能用在线程中。

1.1、互斥锁

(Mutex)

线程中:可以使用。互斥锁用于在线程之间同步访问共享资源,确保同一时刻只有一个线程能访问资源。

进程中:可以使用,但需要跨进程互斥锁(如使用 POSIX 的 pthread_mutexattr_setpshared 设置,或者 Windows 的 CreateMutex 函数),来确保进程间的同步。

1.2、读写锁

(Read-Write Lock)

线程中:可以使用。读写锁允许多个线程同时读取共享资源,但在有写入线程时会阻塞所有其他线程。

进程中:可以使用跨进程的读写锁。通常类似互斥锁的机制,可通过共享内存或文件描述符等方式实现跨进程的读写锁。

1.3、信号量

(Semaphore)

线程中:可以使用。信号量用于在线程之间同步资源访问,并且支持计数机制以控制多线程访问的资源数量。

进程中:可以使用。信号量在进程间同步是常用方式,POSIX 提供了 sem_open 等接口,用于跨进程的信号量实现。

1.4、条件变量

(Condition Variable)

线程中:可以使用。条件变量用于线程间的复杂同步,允许线程等待某个条件的满足再继续执行。

进程中:理论上可以实现,但通常较复杂且不常用。需要使用共享内存或特殊的 IPC 机制来确保跨进程的条件变量。

1.5、自旋锁

(Spinlock)

线程中:可以使用。自旋锁用于短时间的锁定操作,线程在获取锁时会持续占用 CPU 进行尝试,适合短时间锁定的高性能场景。

进程中:可以使用,类似于互斥锁,但用于较短的临界区。

1.6、屏障

(Barrier)

线程中:可以使用。屏障用于在线程间同步某个阶段的执行,所有线程都必须到达屏障点后才能继续。

进程中:通常不使用。因为屏障的主要应用场景在于多线程编程中的阶段性同步。

1.7、消息队列、管道、共享内存

进程中:这些是用于进程间通信(IPC)的同步机制,进程间共享数据或消息的同步常用此类方式。

线程中:不适用。这些机制是为进程间通信设计的,而不是线程间的直接同步工具。

二、同步效率

同步方式哪种效率最高,为什么?

效率最高的同步方式取决于具体的使用场景,通常有以下几点考量:

2.1、自旋锁

(Spinlock)

效率最高的场景:在锁的持有时间极短的情况下,自旋锁可能是最高效的,因为它避免了线程切换的开销。适合在多核 CPU 环境下锁定很短时间的操作,如在操作系统内核中使用。

为什么高效:自旋锁不引起线程上下文切换,避免了操作系统调度的开销。但是如果锁持有时间较长,会造成 CPU 资源的浪费,因此不适合长时间的锁定操作。

2.2、互斥锁

(Mutex)

效率高的场景:在锁持有时间适中的情况下,互斥锁是常见且高效的同步方式。适用于绝大多数多线程编程场景。

为什么高效:互斥锁在竞争不激烈的情况下效率较高,且在高竞争时能避免 CPU 资源的浪费,因为线程在获取不到锁时会被挂起。

2.3、读写锁

(Read-Write Lock)

效率高的场景:适用于读操作远多于写操作的场景。在这些情况下,读写锁能够显著提高并发性和效率。

为什么高效:它允许多个读操作并发执行,而写操作需要独占锁,因而能在读多写少的情况下减少锁争用,提高性能。

2.4、信号量

(Semaphore)

效率高的场景:适用于需要控制访问资源数量的场景,如限流、资源池等。

为什么高效:信号量提供了灵活的计数机制,允许多个线程或进程同时访问受限数量的资源,从而在适当的场景下能最大化资源利用率。

在实际应用中,选择合适的同步方式应考虑到具体的应用需求、性能要求以及并发访问的特点。

没有一种同步方式在所有场景下都是最优的。

阅读 10