c/c++线程--2线程同步
线程同步的方式
1.互斥锁
2.条件变量
3.读写锁
异步方式
信号
同步方式:
3种锁都需要创建和销毁。还有属性参数,默认属性的话,这个参数传NULL。
互斥锁通信机制
- 二元变量,解决线程间同步问题。
- 同步:先后顺序。
- 以排他方式防止数据结构被并发的修改;
控制逻辑:
a.访问前申请,如果处于开锁状态,则申请到该锁,并占有。
如果处于锁定状态,默认阻塞当前线程。
b.只有锁定该互斥锁的线程才能释放该互斥锁,其他线程的操作无效。
初始化,销毁互斥锁
互斥锁,互斥锁属性的变量类型
pthread_mutex_t
pthread_mutexattr_t
/// 成功返回0
/* Initialize a mutex. */
extern int pthread_mutex_init (pthread_mutex_t *__mutex,
const pthread_mutexattr_t *__mutexattr)
__THROW __nonnull ((1));
/* Destroy a mutex. */
extern int pthread_mutex_destroy (pthread_mutex_t *__mutex)
__THROW __nonnull ((1));
申请互斥锁
/// 非阻塞
/* Try locking a mutex. */
extern int pthread_mutex_trylock (pthread_mutex_t *__mutex)
__THROWNL __nonnull ((1));
/// 阻塞
/* Lock a mutex. */
extern int pthread_mutex_lock (pthread_mutex_t *__mutex)
__THROWNL __nonnull ((1));
释放互斥锁
/// !!拥有该锁的线程才能开锁。
/* Unlock a mutex. */
extern int pthread_mutex_unlock (pthread_mutex_t *__mutex)
__THROWNL __nonnull ((1));
条件变量通信机制
不仅互斥的访问变量,而且当且仅当满足一定条件时,线程才会执行。如果只使用互斥锁,那么当出现满足的条件时,还要竞争资源。因此,用互斥锁目标线程可能得不到执行的机会。
条件变量解决:
根据保护数据的当前值来调整线程的行为;类似于信号。
条件变量不能单独使用,必须和互斥锁一起使用。
每个线程对应函数的第一条语句使用锁定互斥量的语句,最后一条语句使用解锁互斥量的语句。
条件变量
pthread_cond_t
pthread_condattr_t
a.创建,销毁
/* Initialize condition variable COND using attributes ATTR, or use
the default values if later is NULL. */
extern int pthread_cond_init (pthread_cond_t *__restrict __cond,
const pthread_condattr_t *__restrict __cond_attr)
__THROW __nonnull ((1));
/* Destroy condition variable COND. */
extern int pthread_cond_destroy (pthread_cond_t *__cond)
__THROW __nonnull ((1));
b.等待等待之前要加互斥锁。
阻塞时,隐含释放关联的互斥锁。没唤醒时,隐含加锁。
/* Wait for condition variable COND to be signaled or broadcast.
MUTEX is assumed to be locked before.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_cond_wait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex)
__nonnull ((1, 2));
/* Wait for condition variable COND to be signaled or broadcast until
ABSTIME. MUTEX is assumed to be locked before. ABSTIME is an
absolute time specification; zero is the beginning of the epoch
(00:00:00 GMT, January 1, 1970).
This function is a cancellation point and therefore not marked with
__THROW. */
extern int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
pthread_mutex_t *__restrict __mutex,
const struct timespec *__restrict __abstime)
__nonnull ((1, 2, 3));
c. 唤醒
隐含释放关联的互斥锁。即使没有线程相应,也会返回成功。
/// 唤醒一个
/* Wake up one thread waiting for condition variable COND. */
extern int pthread_cond_signal (pthread_cond_t *__cond)
__THROWNL __nonnull ((1));
/// 唤醒所有
/* Wake up all threads waiting for condition variables COND. */
extern int pthread_cond_broadcast (pthread_cond_t *__cond)
__THROWNL __nonnull ((1));
在我看来,条件变量更像是一种信号。
程序架构
生产者-消费者
putData()
{
lock();
while(仓库满)
{
wait(hasSlot);
}
put(data);
signal(hasData);
unlock();
}
getData()
{
lock();
while(仓库空)
{
wait(hasData);
}
data = get();
signal(hasSlot);
unlock();
}
读写锁通信机制
互斥锁,条件变量都是互斥的访问临街资源。对于数据的读写操作来说,写写和读写冲突的。如果只是读操作,那么可以不冲突。
如果采用排他的机制来操作,可能会降低效率。
读写锁,就可以解决这样的问题。和数据库的逻辑一样。
控制逻辑:
- 如果申请了读锁,其他线程也可以申请读锁,但是不能申请写锁。
- 如果申请了写锁,其他线程既不能申请读锁,也不能申请写锁。
/* Data structure for read-write lock variable handling. The
structure of the attribute type is not exposed on purpose. */
pthread_rwlock_t rwlock;
pthread_rwlockattr_t rwlockattr;
a. 创建,销毁
/* Initialize read-write lock RWLOCK using attributes ATTR, or use
the default values if later is NULL. */
extern int pthread_rwlock_init (pthread_rwlock_t *__restrict __rwlock,
const pthread_rwlockattr_t *__restrict
__attr) __THROW __nonnull ((1));
/* Destroy read-write lock RWLOCK. */
extern int pthread_rwlock_destroy (pthread_rwlock_t *__rwlock)
__THROW __nonnull ((1));
b. 申请,释放
申请读锁
/* Acquire read lock for RWLOCK. */
extern int pthread_rwlock_rdlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1));
/// 非阻塞
/* Try to acquire read lock for RWLOCK. */
extern int pthread_rwlock_tryrdlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1));
申请写锁
/* Acquire write lock for RWLOCK. */
extern int pthread_rwlock_wrlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1));
/// 非阻塞
/* Try to acquire write lock for RWLOCK. */
extern int pthread_rwlock_trywrlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1));
释放锁--无论是读锁还是写锁
/* Unlock RWLOCK. */
extern int pthread_rwlock_unlock (pthread_rwlock_t *__rwlock)
__THROWNL __nonnull ((1));
说明:
释放逻辑
(1).如果释放读锁,但还有其他线程占用读锁,读锁依然锁定。没有,则解锁。(2).如果释放写锁,则直接解锁。