[基础]多线程锁
作用:用于解决多线程资源同步问题。
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.