同步的实现
条件变量
它的特点就是能直接陷入阻塞pthread_cond_wait()
,等待pthread_cond_signal()
或pthread_cond_broadcast
来唤醒它。
1、创建和注销
条件变量和互斥锁一样,都有静态动态两种创建方式,静态方式使用PTHREAD_COND_INITIALIZER
常量
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
动态方式调用pthread_cond_init()
函数
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)
注销一个条件变量需要调用pthread_cond_destroy
,只有在没有线程在该条件变量上等待的时候才能注销这个条件变量,否则返回EBUSY
。因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否有等待线程。
int pthread_cond_destroy(pthread_cond_t *cond)
2、等待与激发
条件等待pthread_cond_wait()
和计时等待pthread_cond_timedwait()
。
其中计时等待方式如果在给定时刻前条件没有满足,则返回ETIMEDOUT
,结束等待,其中abstime
以与time()
系统调用相同意义的绝对时间形式出现,0表示格林尼治时间1970年1月1日0时0分0秒。
它们的机制都是会把自己陷入阻塞状态,并把锁释放。等待激发的触发(计时等待多一个计时触发)才能加锁并继续运行接下来的语句。
无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()
(或thread_cond_timedwait()
)的竞争条件(Race Condition)。并且要自行手动加锁pthread_mutex_lock()
和释放锁pthread_mutex_unlock()
!
若执行成功,pthread_cond_wait()
函数将返回零。否则将返回一个代表错误的错误码。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
激发条件有两种形式,pthread_cond_signal()
激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()
则激活所有等待线程。
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
信号量
它的特点是维护了一个计数器。
1、初始化
初始化(initialize),也叫做建立(create)
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem
:指向信号量对象
pshared
: 指明信号量的类型。不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享。
value
: 指定信号量值的大小
sem_init
成功时返回 0;错误时,返回 -1,并把 errno 设置为合适的值。
2、等信号
int sem_wait(sem_t *sem);
3、给信号
int sem_post(sem_t *sem);
4、清理
int sem_destory(sem_t *sem);
STL中线程安全的容器
C++标准模板库(STL)中并没有提供专门的线程安全容器。STL的容器是设计为在单线程环境中使用的,因此在多线程环境中使用它们可能导致竞态条件和其他并发问题。
然而,C++11引入了一些线程安全的容器,它们位于 <mutex>
头文件中。这些容器是在多线程环境中安全使用的,因为它们在内部使用了互斥锁(mutex)来保护共享数据。一些线程安全的容器包括:
std::mutex
:互斥锁,用于在多线程中保护共享资源。std::unique_lock
:提供了对互斥锁的独占所有权。std::shared_mutex
:用于支持读写锁的互斥锁。std::lock_guard
:提供了对互斥锁的独占所有权,类似于std::unique_lock
。std::condition_variable
:条件变量,用于在多线程之间同步。
要在多线程环境中安全使用STL容器,你可以使用这些线程安全的工具来手动管理互斥访问。另外,一些第三方库也提供了线程安全版本的STL容器,可以考虑使用它们来简化多线程编程。