一.线程控制:互斥
- 互斥概念:互斥是多线程中对临界资源的排他性访问;互斥机制通过互斥锁来保证临界资源的访问控制。
- 框架:
- 定义互斥锁:
pthread_mutex_t mutex;
- 初始化锁:int pthread_mutex_init(
pthread_mutex_t *mutex,
const pthread_mutexattr_t *attr);
功能:将已经定义好的互斥锁初始化。
参数:mutex-要初始化的互斥锁。
attr-初始化的值,一般是NULL表示默认锁。
返回值:成功为0,失败为非0。 - 加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:用指定的互斥锁开始加锁代码。
加锁后的代码到解锁部分的代码属于原子操作,
在加锁期间其他进线程都不能操作该部分代码。
如果该函数执行时mutex已被其他部分使用,则代码阻塞。
参数:mutex-用来给代码加锁的互斥锁。
返回值:成功为0,失败为非0。 - 解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:将指定的互斥锁解锁。
解锁之后代码不再排他访问,一般加锁解锁同时出现。
参数:mutex-用来解锁的互斥锁。
返回值:成功为0,失败为非0。 - 销毁:int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:使用互斥锁完毕后需要销毁互斥锁。
参数:mutex-用来销毁的互斥锁。
返回值:成功为0,失败为非0。 - 尝试加锁:int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:类似加锁函数效果,唯一区别就是不阻塞。
参数:mutex-用来加锁的互斥锁。
返回值:成功为0,失败为非0。
- 定义互斥锁:
二.线程控制:同步
- 同步概念:同步是有一定先后顺序的对资源的排他性访问,互斥锁相比虽同样可以控制排他性访问,但没有次序。
- 框架:
- 定义信号量:
pthread_mutex_t mutex;
- 初始化信号量:
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:将已经定义好的信号量赋值。
参数:sem-要初始化的信号量
pshared = 0 ;表示线程间使用信号量
!=0 ;表示进程间使用信号量
value-信号量的初始值,一般无名信号量都是二值信号量->
0 表示红灯,进程暂停阻塞
1 表示绿灯,进程可以通过执行
返回值:成功为0,失败为-1。 资源申请:int sem_wait(sem_t *sem);
功能:如果sem有资源(==1),则申请该资源,程序继续运行
如果sem没有资源(==0),则线程阻塞等待,一旦有资源
则自动申请资源并继续运行程序。
注意:sem 申请资源后会自动执行 sem = sem - 1。
参数:sem-要判断的信号量。
返回值:成功为0,失败为-1。- 资源释放:int sem_post(sem_t *sem);
功能:函数可以将指定的sem信号量资源释放并默认执行,
sem = sem+1;
线程在该函数上不会阻塞。
参数:sem-要释放资源的信号量。
返回值:成功为0,失败为-1。 - 销毁信号量: int sem_destroy(sem_t *sem);
功能:使用完毕将指定的信号量销毁。
参数:sem-要销毁的信号量。
返回值:成功为0,失败为-1。
- 定义信号量:
三.死锁生成
1.死锁生成主要原因
- 系统资源不足:当可用资源少于进程需求时,进程可能会因为等待资源而无法继续执行。
- 进程运行推进的顺序不合适:进程请求和释放资源的顺序如果不合理,可能导致循环等待。
- 资源分配不当:不合理的资源分配策略可能导致资源无法有效利用,增加了死锁的风险。
2.死锁生成必要条件
- 互斥条件:每个资源在一段时间内只能由一个进程占有,其他请求该资源的进程必须等待。
- 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而这个请求的资源正被其他进程占有,因此请求进程会被阻塞,但它对已获得的资源不释放。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能被其他进程强行夺走,只能由进程自愿释放。
- 循环等待条件:存在一种进程资源的循环等待关系,即进程间形成一种头尾相接的循环链,每个进程都在等待下一个进程所占有的资源。
四.线程控制代码示例
示例:用多线程程序设计一个火车票售票系统,
要求至少有两个售票窗口,每个售票窗口
不能重复买票,将100张车票均匀的从两个
窗口卖出即可。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
int num=100;
int WIN[2]={1,1};
sem_t sem_WIN;
pthread_mutex_t mutex;
pthread_mutex_t mutex_win;
int get_win()
{
sem_wait(&sem_WIN);
int i = 0 ;
for(i = 0 ;i<2;i++)
{
pthread_mutex_lock(&mutex_win);
if(1==WIN[i])
{
WIN[i] = 0 ;
pthread_mutex_unlock(&mutex_win);
return i;
}else
{
pthread_mutex_unlock(&mutex_win);
}
}
return -1;
}
void relese_win(int id)
{
pthread_mutex_lock(&mutex_win);
WIN[id]=1;
pthread_mutex_unlock(&mutex_win);
sem_post(&sem_WIN);
}
void* th(void* arg)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(num>0)
{
int n = num--;
pthread_mutex_unlock(&mutex);
int id = get_win();
printf("win %d, ticket:%d tid:%lu\n",id+1 ,n,pthread_self());
usleep(1000*100);
relese_win(id);
}else
{
pthread_mutex_unlock(&mutex);
break;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tid1,tid2;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex_win,NULL);
sem_init(&sem_WIN,0,2);
pthread_create(&tid1,NULL,th,NULL);
pthread_create(&tid2,NULL,th,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
sem_destroy(&sem_WIN);
pthread_mutex_destroy(&mutex);
pthread_mutex_destroy(&mutex_win);
return 0;
}