一.线程分离属性
什么是分离属性?
首先分离属性是线程的一个属性,有了分离属性的线程,不需要别的线程去接合自己了(使用pthread_join回收资源)。
设置了分离属性的线程 ->不需要pthread_join()
设置了非分离属性的线程 ->需要pthread_join(),如果在线程创建时,没有设置分离属性时,默认创建的线程就是非分离线程。
通过属性设置线程的分离
1.线程属性类型: pthread_attr_t attr;
2.线程属性操作函数:
对线程属性变量的初始化
int pthread_attr_init(pthread_attr_t* attr);
3.设置线程分离属性
int pthread_attr_setdetachstate(
pthread_attr_t* attr,
int detachstate
);
参数:
attr : 线程属性
detachstate
PTHREAD_CREATE_DETACHED(分离)
PTHREAD_CREATE_JOINABLE(非分离)
4.释放线程资源函数
int pthread_attr_destroy(pthread_attr_t* attr);
二.线程同步
什么是线程同步?
线程同步是指在多个线程并发执行时,保证它们按照一定的顺序执行以达到正确的结果。
按照代码,funA与funB各加10000,number因该加到20000的,但是从结果哪里可以看到它并没有加到两万,这是为什么呢?
全局变量number=0
第一次线程A对其操作,从0加到了100,这个只有写到内存里number才是正在的加到100。假设这种情况,线程A加到100但是没有写到内存里,此时线程A可能失cpu。线程B拿到cpu,线程B是从寄存器里取number的值的,因为线程A没有将其值写到内存中,所以此时线程B的number取值是0。假设线程B从0写到了200写入了内存里,失去cpu权限,这时number值是200。所以会出现没有加到两万的现象。
为什么会这样子?
因为线程A、B是在相互抢占共享资源的。
如何解决?
线程同步
三.互斥量(互斥锁)
1.互斥锁类型:
创建一把锁: pthread_mutex_t mutex;
2.互斥锁的特点:
多个线程访问共享数据的时候是串行的
3.使用互斥锁缺点
效率低
4.互斥锁使用的步骤
1.创建互斥锁: pthread_mutex_t mutex;
2.初始化:pthread_mutex_init(&mutex,NULL); -- mutex = 1
3.找到线程共同操作的共享数据
比如在两个线程中使用全局变量number,就需要在两个进程中使用共享数据之前加上同一锁,使用后解锁
4.加锁:操作共享资源之前加锁,pthread_mutex_lock(&mutex); //阻塞 --mutex = 0
pthread_mutex_trylock(&mutex); // 如果锁上锁直接返回,不阻塞
XXXXXX共享数据操作 //临界区 ,越小越好
5.解锁:pthread_mutex_unlock(&mutex); // -- mutex = 1
阻塞在锁上的线程会被唤醒
6.销毁:pthread_mutex_destory(&mutex);
5.互斥锁相关函数:
初始化互斥锁
pthread_mutex_init(
pthread_mutex_t* restrict mutex,
const pthread_mutexattr_t* restrict attr,
);
销毁互斥锁:
pthread_mutex_destory(pthread_mutex_t* mutex );
加锁
pthread_mutex_lock(pthread_mutex* mutex);
mutex:
没有被锁上,当前线程会将这把锁锁上
被锁上了:当前线程阻塞,锁被打开之后,线程解除阻塞
尝试加锁,失败返回,不阻塞
pthread_mutex_trylock(pthread_mutex_t* mutex);
没有锁上:当前线程会被这把锁加锁
如果锁上了:不会阻塞,返回
返回0:加锁 成功。没锁上:返回错误号
if( pthread_mutex_trylock(& mutex)==0)
{
//尝试加锁,并且成功了
//访问共享资源
XXXXXXXX
}
else
{
//错误处理
//或者等待,再次尝试加锁
}
解锁
pthread_mutex_unlock(pthread_mutex_t* mutex);
如果我们想要使用互斥锁同步线程所以线程都需要加锁
下面给上面写的代码中的两个线程使用共享资源部分的代码加上互斥锁,加上锁之后可以看到原型结果就是两万了
注意:
是对共享数据进行加锁,加速解锁的共享数据临界区越小越好