pthread线程的控制
目录
- 1. Linux基础命令笔记
- 1.1 常用命令
- 1.2 网络配置
- 2. 线程控制:互斥与同步
- 2.1 基本概念
- 2.2 操作框架
- 2.2.1 定义锁
- 2.2.2 初始化锁
- 2.2.3 加锁/解锁
- 2.2.4 销毁锁
- 2.3 互斥锁示例
- 2.4 互斥练习
- 练习1
- 练习2
- 3. 线程同步机制(排他和顺序)
- 3.1 计数信号量机制
- 3.2 信号量操作框架
- 3.2.1 初始化
- 3.2.2 PV操作
- 3.3 同步练习
- 4. 综合案例
- 4.1 火车票售票系统
- 4.2 餐厅模拟系统
- 5. 线程高级特性
- 5.1 线程属性控制
- 5.2 线程调度
- 6. 死锁分析
- 6.1 产生原因
- 6.2 必要条件(任意出现一个都会出现死锁)
1. Linux基础命令笔记
1.1 常用命令
man pthread_mutex_init
ping www.baidu.com
sudo apt-get install manpages-posix manpages-posix-dev
1.2 网络配置
vim /etc/network/interface
auto lo
iface lo inet loopbackauto eth0
iface eth0 inet dhcpvim /etc/resolv.conf
nameserver 8.8.8.8sudo /etc/init.d/networking restart
ifconfig
改软件源...
sudo apt-get update
2. 线程控制:互斥与同步
2.1 基本概念
互斥 ===》在多线程中对临界资源的排他性访问
互斥机制 ===》互斥锁 ===》保证临界资源的访问控制
pthread_mutex_t mutex;
互斥锁类型 互斥锁变量 内核对象
同步是互斥的特例:
2.2 操作框架
定义互斥锁 ==》初始化锁 ==》加锁 ==》解锁 ==》销毁
2.2.1 定义锁
pthread_mutex_t mutex;
放在线程启动之前
2.2.2 初始化锁
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
功能:初始化已定义的互斥锁
参数:
- mutex: 要初始化的锁
- attr: 通常为NULL表示默认
返回值:成功0,失败非零
2.2.3 加锁/解锁
int pthread_mutex_lock(pthread_mutex_t *mutex); // 阻塞式加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex); // 解锁
int pthread_mutex_trylock(pthread_mutex_t *mutex); // 非阻塞加锁
2.2.4 销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
2.3 互斥锁示例
int a = 0;
while(5000--) {int temp = a;printf("%d",temp+1);a = temp+1;
}
程序完整代码如下:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>int count = 0;
pthread_mutex_t mutex;
void* th(void* th)
{int i = 5000;while (i--){// count++pthread_mutex_lock(&mutex);int tmp = count;// pthread_mutex_unlock(&mutex);printf("%d\n", tmp + 1);// pthread_mutex_lock(&mutex);//sleep(1);count = tmp + 1;pthread_mutex_unlock(&mutex);}return NULL;
}int main(int argc, char** argv)
{pthread_t tid1, tid2;pthread_mutex_init(&mutex, NULL);pthread_create(&tid1, NULL, th, NULL);pthread_create(&tid2, NULL, th, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex);// system("pause");return 0;
}
银行十个人取钱三个窗口例子(10个线程)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int WIN = 3;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
;
void* th(void* arg)
{while (1){pthread_mutex_lock(&mutex);if (WIN > 0){WIN--;pthread_mutex_unlock(&mutex);printf("get win...\n");sleep(rand() % 5);printf("relese win...\n");pthread_mutex_lock(&mutex);WIN++;pthread_mutex_unlock(&mutex);break;}else{pthread_mutex_unlock(&mutex);}}return NULL;
}int main(int argc, char** argv)
{int i = 0;srand(time(NULL));pthread_t tid[10] = {0};// pthread_mutex_init();for (i = 0; i < 10; ++i){pthread_create(&tid[i], NULL, th, NULL);}for (i = 0; i < 10; ++i){pthread_join(tid[i], NULL);}pthread_mutex_destroy(&mutex);// system("pause");return 0;
}
2.4 互斥练习
练习1
设计多线程程序共享字符数组,用堆区/栈区互斥锁保证排他访问
练习2
多线程同时写文件,要求信息不覆盖不交叉
3. 线程同步机制(排他和顺序)
同步的概念:有一定先后顺序的排他性访问
同步和互斥都可以当年互斥锁用
互斥是必须谁上锁,谁就解锁
3.1 计数信号量机制
#include <semaphore.h>
分类:
- 无名信号量(线程间)
- 有名信号量(进程间)
信号量的定义:
sem_t sem
信号量的类型 信号量的变量
3.2 信号量操作框架
定义信号量 → 初始化 → PV操作 → 销毁
1、信号量的定义:
sem_t sem
信号量的类型 信号量的变量
2、信号量的初始化
3.2.1 初始化
int sem_init(sem_t *sem, int pshared, unsigned int value);
pshared=0表示线程间
3.2.2 PV操作
int sem_wait(sem_t *sem); // P操作
int sem_post(sem_t *sem); // V操作
1)int sem_wait(sem_t*sem);
功能:判断当前sem信号量是否有资源可用
如果sem有资源(==1),则申请该资源;程序继续运行;
如果sem没有资源(==0)则线程阻塞等待,一旦有资源
则自动申请资源继续运行程序;
注意事项:
sem申请后会自动执行 sem = sem-1;
参数:sem要判断的信号量资源;
返回值:成功0
失败-1
2)int sem_postpost(sem_t*sem);
功能:函数可以将指定的sem信号量资源释放,并默认执行,sem = sem+1
线程在该函数上不会阻塞
参数:sem要释放资源的信号量
返回值:成功-0;失败:-1;
举例代码如下:(hello world)
3)int sem——destroy(sem_t *sem);
功能:使用完毕后将指定的信号量销毁
参数:sem要销毁的信号量;
返回值:成功-0;失败-1;
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
sem_t sem_H, sem_W;
void* th1(void* arg)
{int i = 10;while (i--){// 申请信号量(P) sem_H -1 >=0 代表申请成功 代码继续执行// 否则,线程阻塞sem_wait(&sem_H);printf("hello, ");// sem_w +1 .释放信号量. 释放的是,下一个同步事件的信号量sem_post(&sem_W);fflush(stdout);}return NULL;
}void* th2(void* arg)
{int i = 10;while (i--){sem_wait(&sem_W);printf("world\n");sem_post(&sem_H);sleep(1);}return NULL;
}
int main(int argc, char** argv)
{pthread_t tid1, tid2;sem_init(&sem_H, 0, 1);sem_init(&sem_W, 0, 0);pthread_create(&tid1, NULL, th1, NULL);pthread_create(&tid2, NULL, th2, NULL);pthread_join(tid1, NULL);pthread_join(tid2, NULL);sem_destroy(&sem_H);sem_destroy(&sem_W);// system("pause");return 0;
}
3)semaphore
int sem_init(sem_t*sem,int pshared,unsignedinteresting value);
功能:将已经定义好的信号赋值、
参数:sem-要初始化的信号量
pshared=0;表示线程间使用信号量
value信号量的初始值,一般无名信号量
都是二值信号量,0,1
返回值:成功-0
失败:-1
计数信号量的举例代码:
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>sem_t sem_win;
void* th(void* arg)
{// 申请信号量 sem_win -1 . >=0,否则阻塞sem_wait(&sem_win);printf("get win...\n");sleep(rand() % 5);printf("relese win...\n");sem_post(&sem_win); // 释放信号量 sem_win + 1return NULL;
}int main(int argc, char** argv)
{int i = 0;srand(time(NULL));pthread_t tid[10] = {0};//计数信号量, 互斥类型,同类型资源数是多个的情况sem_init(&sem_win, 0, 3);for (i = 0; i < 10; ++i){pthread_create(&tid[i], NULL, th, NULL);}for (i = 0; i < 10; ++i){pthread_join(tid[i], NULL);}sem_destroy(&sem_win);// system("pause");return 0;
}
3.3 同步练习
要求:
- 最少线程和信号量
- 线程1获取用户输入
- 线程2统计输入长度
- 输入"quit"退出
4. 综合案例
大模型线程池:
4.1 火车票售票系统
要求:
- ≥2个售票窗口
- 均匀卖出100张票
输出示例:
窗口1 卖出车票 1
窗口2 卖出车票 2
4.2 餐厅模拟系统
// 结构体定义
struct {char name[100];int total_num;int call_num;pthread_mutex_t lock;
} record;
5. 线程高级特性
5.1 线程属性控制
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_detach(thread);
5.2 线程调度
pthread_yield();
usleep(1000);
6. 死锁分析
6.1 产生原因
- 系统资源不足
- 进程推进顺序不当
- 资源分配不当
如果系统资源充足,,进程的资源请求都能够得到满足,死锁出现的可能性较低,否则就会因为为争夺有限的资源而陷入死锁,其次,进程运行推进顺利与速度不停,也可能产生死锁。
6.2 必要条件(任意出现一个都会出现死锁)
- 互斥条件 :一个资源每次只能被一个进程使用;
- 请求与保持 :一个进程因请求资源而阻塞时,对已经获得的资源保持不放;
- 不剥夺条件 :进程已获得的资源,在未使用完之前,不能强行剥夺;
- 循环等待条件:循环等待条件就是若干进程之间形成以一种头尾相接的循环等待资源关系