pthread_detach错误码:

注意:这里的已分离不是指线程失去控制,不归线程组管,而是指线程退出后,系统会自动释放线程资源。若是线程组内的任意线程执行了exit函数,即使是已分离的线程,也仍会收到影响,一并退出。
6.线程安全
线程安全中涉及到的概念:
临界资源:多线程中都能访问到的资源临界区:每个线程内部,访问临界资源的代码,就叫临界区
6.1什么是线程不安全?
多个线程访问同一块临界资源,导致资源产生二义性的现象。
6.1.1举一个例子
假设现在有两个线程A和B,单核CPU的情况下,此时有一个int类型的全局变量为100,A和B的入口函数都要对这个全局变量进行–操作。
线程A先拿到CPU资源后,对全局变量进行–操作并不是原子性操作,也就是意味着,A在执行–的过程中有可能会被打断。假设A刚刚将全局变量的值读到寄存器当中,就被切换出去了,此时程序计数器保存了下一条执行的指令,上下文信息保存寄存器中的值,这两个东西是用来线程A再次拿到CPU资源后,恢复现场使用的。
此时,线程B拿到了CPU资源,对全局变量进行了–操作,并且将100减为了99,回写到了内存中。
A再次拥有了CPU资源后,恢复现场,继续往下执行,从寄存器中读到的值仍为100,减完之后为99,回写到内存中为99。
上述例子中,线程A和B都对全局变量进行了–操作,全局变量的值应该变为98,但程序现在实际的结果为99,所以这就导致了线程不安全。
6.2如何解决线程不安全现象?
解决方案只需做到下述三点即可:
1、代码必须要有互斥的行为: 当一个线程正在临界区中执行时, 不允许其他线程进入该临界区中。
2、如果多个线程同时要求执行临界区的代码, 并且当前临界区并没有线程在执行, 那么只能允许一个线程进入该临界区。
3、如果线程不在临界区中执行, 那么该线程不能阻止其他线程进入临界区。
则本质上,我们需要对该临界区加一把锁:

锁是一个很普遍的需求, 当然用户可以自行实现锁来保护临界区。 但是实现一个正确并且高效的锁非常困难。 纵然抛下高效不谈, 让用户从零开始实现一个正确的锁也并不容易。 正是因为这种需求具有普遍性, 所以Linux提供了互斥量。
6.3互斥量接口
6.3.1互斥量的初始化
1、静态分配:
#include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
2、动态分配:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

调用int pthread_mutex_init()函数后,互斥量是处于没有加锁的状态。
6.3.2互斥量的销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
注意:
1、使用PTHREAD_MUTEX_INITIALIZER初始化的互斥量无须销毁。
2、不要销毁一个已加锁的互斥量, 或者是真正配合条件变量使用的互斥量。
3、已经销毁的互斥量, 要确保后面不会有线程再尝试加锁。
当互斥量处于已加锁的状态, 或者正在和条件变量配合使用, 调用pthread_mutex_destroy函数会返回EBUSY错误码。
6.3.3互斥量的加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);
第一个接口:int pthread_mutex_lock(pthread_mutex_t *mutex);
1、该接口是阻塞加锁接口。
2、mutex为传入互斥锁变量的地址
3、如果mutex当中的计数器为1,pthread_mutex_lock接口就返回了,表示加锁成功,同时计数器当中的值会被更改为0.
4、如果mutex当中的计数器为0,pthread_mutex_lock接口就阻塞了,pthread_mutex_lock接口没有返回了,阻塞在函数内部,直到加锁成功
第二个接口:int pthread_mutex_trylock(pthread_mutex_t *mutex);
1、该接口为非阻塞接口
2、mutex中计数器为1时,加锁成功,计数器置为0,然后返回