[基础]多线程锁




作用:用于解决多线程资源同步问题。

1. 互斥量(mutex)

操作系统或者clib都有提供,mutex是睡眠等待(sleep waiting)类型的锁, 当线程抢锁失败时,会进入休眠。

优点:节省CPU资源

缺点:休眠唤醒会消耗一点时间

1// pthread example
2// 声明一个互斥量
3pthread_mutex_t mtx;
4// 初始化 
5pthread_mutex_init(&mtx, NULL);
6// 加锁  
7pthread_mutex_lock(&mtx);
8// 解锁 
9pthread_mutex_unlock(&mtx);
10// 销毁
11pthread_mutex_destroy(&mtx);

2. 自旋锁(spinlock)

mutex的死循环版本,即线程不会休眠,一直循环等待抢锁。

在特别要求性能时使用。

1// 原子操作版本  (from skynet)
2struct spinlock {
3	atomic_flag_ lock;
4};
5
6static inline void
7spinlock_init(struct spinlock *lock) {
8	atomic_flag_ v = ATOMIC_FLAG_INIT_;
9	lock->lock = v;
10}
11
12static inline void
13spinlock_lock(struct spinlock *lock) {
14	while (atomic_flag_test_and_set_(&lock->lock)) {}
15}
16
17static inline int
18spinlock_trylock(struct spinlock *lock) {
19	return atomic_flag_test_and_set_(&lock->lock) == 0;
20}
21
22static inline void
23spinlock_unlock(struct spinlock *lock) {
24	atomic_flag_clear_(&lock->lock);
25}
26
27static inline void
28spinlock_destroy(struct spinlock *lock) {
29	(void) lock;
30}

3. 条件变量(condition variable)

当满足条件时,线程被唤醒,否则一直休眠。

使用场景:生产者/消费者模式

1// from skynet
2struct message_queue * q = NULL;
3	while (!m->quit) {
4		q = skynet_context_message_dispatch(sm, q, weight);
5		if (q == NULL) {
6			if (pthread_mutex_lock(&m->mutex) == 0) {
7				++ m->sleep;
8				// "spurious wakeup" is harmless,
9				// because skynet_context_message_dispatch() can be call at any time.
10				if (!m->quit)
11					pthread_cond_wait(&m->cond, &m->mutex);
12				-- m->sleep;
13				if (pthread_mutex_unlock(&m->mutex)) {
14					fprintf(stderr, "unlock mutex error");
15					exit(1);
16				}
17			}
18		}
19	}

注意:skynet中不处理“虚假唤醒”(spurious wakeup),而在一般情况下通常需要用while()循环来代替if(!m->quit).

4. 读写锁(read-write lock)

对共享资源读多写少的情况下使用。

读写锁的特性:

  • 当读写锁被加了写锁时,其他线程对该锁加读锁或者写锁都会阻塞(不是失败)。
  • 当读写锁被加了读锁时,其他线程对该锁加写锁会阻塞,加读锁会成功
1// 原子操作版本 from skynet
2struct rwlock {
3	ATOM_INT write;
4	ATOM_INT read;
5};
6
7static inline void
8rwlock_init(struct rwlock *lock) {
9	ATOM_INIT(&lock->write, 0);
10	ATOM_INIT(&lock->read, 0);
11}
12
13static inline void
14rwlock_rlock(struct rwlock *lock) {
15	for (;;) {
16		while(ATOM_LOAD(&lock->write)) {}
17		ATOM_FINC(&lock->read);
18		if (ATOM_LOAD(&lock->write)) {
19			ATOM_FDEC(&lock->read);
20		} else {
21			break;
22		}
23	}
24}
25
26static inline void
27rwlock_wlock(struct rwlock *lock) {
28	while (!ATOM_CAS(&lock->write,0,1)) {}
29	while(ATOM_LOAD(&lock->read)) {}
30}
31
32static inline void
33rwlock_wunlock(struct rwlock *lock) {
34	ATOM_STORE(&lock->write, 0);
35}
36
37static inline void
38rwlock_runlock(struct rwlock *lock) {
39	ATOM_FDEC(&lock->read);
40}

2023-11-22


© 2024 Jay. All Rights Reserved.