一、线程的分离属性
线程结束后,自动回收线程空间
1. pthread_attr_init
int pthread_attr_init(pthread_attr_t *attr);
功能:线程属性初始化
2. pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
功能:线程属性销毁
3. pthread_attr_setdetachstate
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
功能:设置分离属性
PTHREAD_CREATE_DETACHED 分离属性
PTHREAD_CREATE_JOINABLE 加入属性(默认)
示例:
#include "head.h"
void *thread1(void* argc)
{
printf("线程1(%#x)正在运行...\n",(unsigned int)pthread_self());
return NULL;
}
void *thread2(void* argc)
{
printf("线程2(%#x)正在运行...\n",(unsigned int)pthread_self());
return NULL;
}
void *thread3(void* argc)
{
printf("线程3(%#x)正在运行...\n",(unsigned int)pthread_self());
return NULL;
}
int main(void)
{
pthread_t pid[3];
void*(*p[3])(void *) = {thread1,thread2,thread3};
int i = 0;
pthread_attr_t attr; //创建一个线程属性变量
pthread_attr_init(&attr); //对线程属性初始化
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //定义为分离属性
for (i = 0; i < 3; ++i)
{
pthread_create(&pid[i],&attr,p[i],NULL);
}
pthread_attr_destroy(&attr); //回收销毁掉线程属性
while(1)
{
}
return 0;
}
二、线程互斥
1.互斥锁:(多线程操作全局变量时加锁)
防止资源竞争
2.函数接口:
1)pthread_mutex_init;
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
功能:互斥锁初始化
参数:
mutex:互斥锁空间首地址
attr:互斥锁的属性(默认为NULL)
返回值:成功返回0;失败返回错误码
2)pthread_mutex_destroy;
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:互斥锁销毁
参数:
mutex:互斥锁空间首地址
返回值:成功返回0;失败返回错误码
3)pthread_mutex_lock;
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:上锁
参数:锁的地址
4)pthread_mutex_unlock:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:锁的地址
3、临界资源、临界区
加锁解锁中间的代码成为临界资源、临界区
同一时刻临界资源不能同时执行,只能执行其中一个临界代码
4、原子操作
CPU最小的一次不能被任务调度打断的操作称为原子操作
5、互斥锁的特点
互斥锁只能解决资源竞争的问题;不能解决同步的问题
示例:
#include "head.h"
pthread_mutex_t lock; //定义一个互斥锁的类型 命名为lock
int num = 0;
void *thread1(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock); //上锁
num = 100;
pthread_mutex_unlock(&lock); //解锁
}
return NULL;
}
void *thread2(void *arg)
{
while(1)
{
pthread_mutex_lock(&lock);
num = 200;
printf("num = %d\n",num);
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main(void)
{
pthread_t tid1;
pthread_t tid2;
pthread_mutex_init(&lock,NULL); //对互斥锁初始化
pthread_create(&tid1,NULL,thread1,&num);
pthread_create(&tid2,NULL,thread2,&num);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_mutex_destroy(&lock); //销毁互斥锁
return 0;
}
打印结果全是:num=200
注意:两个线程的临界代码都要上锁
原因:宏观并行;微观串行
三、死锁
多线程操作互斥锁,导致多个线程均无法向下执行的状态成为死锁状态简称死锁
1.死锁产生的四个必要条件:
1)互斥条件
2)不可剥夺条件
3)请求保持
4)循环等待
2.避免产生死锁:
1)pthread_mutex_trylock(尝试加锁)替代 pthread_mutex_lock
2)加锁顺序保持一致
四、信号量
信号量时一种资源,可以被初始化、申请、释放、销毁。
p操作:申请资源
v操作:释放资源
1.sem_init
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化信号量
参数:
sem:信号量空间首地址
pshared:0 一个进程中所有线程共享
非0 进程间共享
返回值:
成功返回0
失败返回-1
2.sem_destroy:
int sem_destroy(sem_t *sem);
功能:信号量的销毁
参数:
sem:信号量空间首地址
返回值:成功放回0;失败返回-1
3.sem_wait:
int sem_wait(sem_t *sem);
功能:申请信号量
4.sem_post:
int sem_post(sem_t *sem);
功能:释放信号量
示例:
#include "head.h"
char tempuff[4096] = {0};
sem_t sem_w; //定义一个资源量类型的写变量
sem_t sem_r; //定义一个资源量类型的读变量
void *thread1(void *arg)
{
while(1)
{
sem_wait(&sem_w); //申请一个写信号
gets(tempuff);
sem_post(&sem_r); //释放一个读信号
}
return NULL;
}
void *thread2(void *arg)
{
while(1)
{
sem_wait(&sem_r); //申请一个读信号
printf("tempuff = %s\n",tempuff);
sem_post(&sem_w); //释放一个写信号
}
return NULL;
}
int main(void)
{
pthread_t tid1;
pthread_t tid2;
sem_init(&sem_w,0,1); //对写变量初始化 定义在线程中 给到一个资源
sem_init(&sem_r,0,0); //对读变量初始化 定义在线程中 给零个资源
pthread_create(&tid1,NULL,thread1,NULL);
pthread_create(&tid2,NULL,thread2,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
sem_destroy(&sem_w); //销毁写
sem_destroy(&sem_r); //销毁读
return 0;
}
作用:能用来保持多线程中保持程序的同步性;一个执行、一个等待,依次运行。