一、异常
(1)异常类型
注意:linux中断是异常的一种,异常包含中断,有软件中断(swi svc指令触发)、快速中断、外部中断三种与中断有关的异常。
(2)IRQ中断流程
1.cpu每个指令周期检查是否发送异常;
2.若发现异常,保存CPSR(程序状态寄存器),将当前处理模式设置为ARM、IRQ模式,将被打断应用程序地址的下一个指令保存到LR寄存器,例如当前程序地址为0x6000008,LR为0x6000004,即下一个指令的地址;
3.PC指针指向0x18,程序到0x18取出指令,这个指令跳转到中断异常处理函数;
4.中断异常处理函数中,分三步处理;
①保护现场:寄存器、CPU状态入栈
②根据中断号,跳转到对应的中断处理函数中执行
③执行完毕恢复现场:寄存器、CPU状态出栈
5.恢复现场后,PC指向原来中断的地方,重新回到断点执行程序;
(3)中断处理函数原则
中断处理函数是一个特俗的函数,可以从参数、返回值、函数内部实现回答
1.参数和返回值:绝对不能传入参数,不能返回值;
2.内部实现:
①快进快出原则,中断处理函数的任务要尽可能快速完成,以免堵塞其他中断;
②根据①原则,中断处理函数不能休眠,如调用sleep;
③中断处理函数不能调用不可重入函数(记为fun),以免主函数mian正在执行;fun,中断又来执行fun,导致fun内部的全局变量和静态变量的结果出乎意料。
(4)不可重入函数的特点
1.使用了全局变量和静态变量;
2.返回了全局变量和静态变量;
3.调用了不可重入函数,这点难以防范,因为很多时候并不清除调用的第三方函数内部如何实现,是否可重入;
4.使用了标准IO函数,如调用了scanf,printf;
5.使用了malloc,free函数
二、c线程池
(1)线程池简介
线程的创建和销毁是资源密集型的操作,设计操作系统的系统调度和资源分配,频繁的创建和销毁线程会造成资源浪费,并使得系统响应速度降低。线程池通过预先创建线程,并在后续重复利用这些线程,有效避免了在任务执行过程中频繁创建和销毁线程,从而降低资源消耗,提高系统的响应速度;
线程池作用:
1.使得线程可重复利用,降低频繁创建和销毁线程造成的资源消耗,提高系统响应速度;
2.避免线程过多导致系统资源耗尽;
3.线程池可以动态调整线程数量,适应不同的工作负荷;
(2)c语言实现线程池
数据:定义一个TheradPool结构体,结构体内主要包括一个线程队列、一个任务队列、互斥锁和条件变量以及一些用于记录任务和线程数量的变量;
初始化:首先创建线程,将线程放入线程队列,分配内存空间,初始化条件变量和互斥锁;
管理者线程:线程池主要实现工作(消费者)线程和一个管理者线程,管理则线程用于管理线程的创建和销毁,管理者检测到运行过程中线程的数量不足时将创建新的线程,若是检测到有大量空闲的线程,则销毁一部分线程,将资源归还给操作系统。
工作线程:工作线程数量数量有多个,每个工作线程首先会尝试获取线程池锁,等待任务队列非空的条件变量,等到了条件变量则从任务队列中取出一个任务执行,并向生产者发出任务队列空闲的条件变量。对外提供addTask函数,用于将任务添加到现场池,若是线程池中有可用的线程资源,直接取出一个线程执行任务;若是没有可用的线程资源则阻塞,等待工作线程发空闲信号。
#ifndef _THREAD_POOL_H__
#define _THREAD_POOL_H__
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#define ADD_NUMBER 2
// 任务结构体
typedef struct Task {
void (*function)(void* arg);
void* arg;
} Task;
// 线程池结构体
typedef struct ThreadPool {
// 任务队列
Task* tq;
int taskCapacity; // 容量
int taskNum; // 当前任务个数
int taskFront; // 队头 -> 取数据
int taskRear; // 队尾 -> 放数据
pthread_t mt; // 管理者线程ID
pthread_t* wt; // 工作的线程ID
int minNum; // 最小线程数量
int maxNum; // 最大线程数量
int busyNum; // 忙的线程的个数
int liveNum; // 存活的线程的个数
int exitNum; // 要销毁的线程个数
pthread_mutex_t mutexPool; // 锁整个的线程池
pthread_mutex_t mutexBusy; // 锁busyNum变量
pthread_cond_t notFull; // 任务队列是不是满了
pthread_cond_t notEmpty; // 任务队列是不是空了
int shutdown; // 是不是要销毁线程池, 销毁为1, 不销毁为0
} ThreadPool;
typedef struct Arg {
int num;
int id;
} Arg;
int max(int a, int b);
int min(int a, int b);
// 创建线程池并初始化
ThreadPool* threadPoolCreate(int min, int max, int taskSize);
// 销毁线程池
int threadPoolDestroy(ThreadPool* pool);
// 给线程池添加任务
void addTask(ThreadPool* pool, void (*func)(void*), void* arg);
// 获取线程池中工作的线程的个数
int threadPoolBusyNum(ThreadPool* pool);
// 获取线程池中活着的线程的个数
int threadPoolAliveNum(ThreadPool* pool);
//
// 工作的线程(消费者线程)任务函数
void* worker(void* arg);
// 管理者线程任务函数
void* manager(void* arg);
// 单个线程退出
void threadExit(ThreadPool* pool);
#endif // _THREADPOOL_H
#include <thread_pool.h>
// 创建线程池并初始化
ThreadPool* threadPoolCreate(int min, int max, int taskSize) {
ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
pool->wt = (pthread_t *)malloc(max * sizeof(pthread_t));
memset(pool->wt, 0, max * sizeof(pthread_t));
pool->taskFront = 0;
pool->taskRear = 0;
pool->taskNum = 0;
pool->taskCapacity = taskSize;
pool->minNum = min;
pool->maxNum = max;
pool->liveNum = min;
pool->exitNum = 0;
pthread_mutex_init(&pool->mutexBusy, NULL);
pthread_mutex_init(&pool->mutexPool, NULL);
pthread_cond_init(&pool->notFull, NULL);
pthread_cond_init(&pool->notEmpty, NULL);
pool->tq = (Task *)malloc(sizeof(Task) * taskSize);
pthread_create(&pool->mt, NULL, manager, pool);
for(int i = 0; i < min; i++) {
pthread_create(&pool->wt[i], NULL, worker, pool);
}
return pool;
}
// 销毁线程池
int threadPoolDestroy(ThreadPool* pool) {
printf("destory:%d\r\n", pool->liveNum);
pool->shutdown = 1;
pthread_join(pool->mt, NULL);
for(int i = 0; i < pool->liveNum; i++) {
// pthread_join(pool->wt[i], NULL);
pthread_cond_signal(&pool->notEmpty);
}
free(pool->wt);
free(pool->tq);
pthread_mutex_destroy(&pool->mutexPool);
pthread_mutex_destroy(&pool->mutexBusy);
pthread_cond_destroy(&pool->notEmpty);
pthread_cond_destroy(&pool->notFull);
free(pool);
return 0;
}
// 获取线程池中工作的线程的个数
int threadPoolBusyNum(ThreadPool* pool) {
int num = 0;
pthread_mutex_lock(&pool->mutexBusy);
num = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
return num;
}
// 获取线程池中活着的线程的个数
int threadPoolAliveNum(ThreadPool* pool) {
int num = 0;
pthread_mutex_lock(&pool->mutexPool);
num = pool->liveNum;
pthread_mutex_unlock(&pool->mutexPool);
return num;
}
// 给线程池添加任务
void addTask(ThreadPool* pool, void (*func)(void*), void* arg) {
pthread_mutex_lock(&pool->mutexPool);
if(pool->shutdown) {
pthread_mutex_unlock(&pool->mutexPool);
return ;
}
if(pool->taskNum == pool->taskCapacity) {
// 队列已满,阻塞生产者线程
pthread_cond_wait(&pool->notFull, &pool->mutexPool);
}
pool->tq[pool->taskRear].function = func;
pool->tq[pool->taskRear].arg = arg;
pool->taskRear = (pool->taskRear + 1) % pool->taskCapacity;
pool->taskNum++;
pthread_cond_signal(&pool->notEmpty);
pthread_mutex_unlock(&pool->mutexPool);
}
// 工作的线程(消费者线程)任务函数
void* worker(void* arg) {
ThreadPool *pool = (ThreadPool *)arg;
while(1) {
pthread_mutex_lock(&pool->mutexPool);
while(pool->taskNum == 0 && pool->shutdown == 0) {
pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);
if(pool->exitNum > 0) {
// printf("worker exit num: %d %lu\r\n", pool->exitNum, pthread_self());
pool->exitNum--;
if(pool->liveNum > pool->minNum) {
pool->liveNum--;
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
}
}
// printf("running %lu\r\n", pthread_self());
if(pool->shutdown) {
// printf("shoutdown %lu\r\n", pthread_self());
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
Task t = pool->tq[pool->taskFront];
pool->taskFront = (pool->taskFront + 1) % pool->taskCapacity;
pool->taskNum--;
pthread_cond_signal(&pool->notFull);
pthread_mutex_unlock(&pool->mutexPool);
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum++;
pthread_mutex_unlock(&pool->mutexBusy);
printf("%lu start\r\n", pthread_self());
t.function(t.arg);
printf("%lu end\r\n", pthread_self());
free(t.arg);
t.arg = NULL;
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum--;
pthread_mutex_unlock(&pool->mutexBusy);
}
}
// 单个线程退出
void threadExit(ThreadPool* pool) {
pthread_t tid = pthread_self();
for(int i = pool->maxNum - 1; i >= 0; i--) {
if(tid == pool->wt[i]) {
pool->wt[i] = 0;
printf("threadExit() called, %ld exiting...\n", tid);
break;
}
}
pthread_exit(NULL);
}
int max(int a, int b) {return a > b ? a : b;}
int min(int a, int b) {return a < b ? a : b;}
// 管理者线程任务函数
void* manager(void* arg) {
ThreadPool * pool = (ThreadPool *)arg;
while(pool->shutdown == 0) {
sleep(3);
pthread_mutex_lock(&pool->mutexBusy);
int busyNum = pool->busyNum;
pthread_mutex_unlock(&pool->mutexBusy);
pthread_mutex_lock(&pool->mutexPool);
int taskNum = pool->taskNum;
int liveNum = pool->liveNum;
int maxNum = pool->maxNum;
printf("live num: %d -- create num : %d -- total num : %d\r\n", pool->liveNum, min(taskNum, maxNum) - liveNum, min(taskNum, maxNum));
// 线程不足 创建线程 创建后使得所有任务都已一个线程,若是创建线程数量超出线程数量限制,则区线程最大数量-当前线程数
for(int n = min(taskNum, maxNum) - liveNum; n > 0; n--) {
pthread_create(&pool->wt[pool->liveNum++], NULL, worker, pool);
}
// 一半的线程空闲, 并且线程数量,则释放线程
if(pool->busyNum * 2 < pool->liveNum) {
pool->exitNum = pool->liveNum - max(pool->minNum, pool->busyNum);
printf("live num : %d ---- exit num: %d\r\n", pool->liveNum, pool->exitNum);
for(int i = pool->exitNum; i > 0; i--) {
pthread_cond_signal(&pool->notEmpty);
}
}
pthread_mutex_unlock(&pool->mutexPool);
}
return NULL;
}
void taskFunc(void* arg)
{
int num = *(int*)arg;
printf("thread %ld is working, number = %d\n",
pthread_self(), num);
sleep(1);
}
int main()
{
// 创建线程池
ThreadPool* pool = threadPoolCreate(3, 10, 100);
for (int i = 0; i < 100; i++)
{
int* num = (int*)malloc(sizeof(int));
*num = i + 100;
addTask(pool, taskFunc, num);
}
sleep(30);
threadPoolDestroy(pool);
return 0;
}
3.bug分析
现象:
管理者线程销毁一个线程后程序卡死
分析:
管理则并不直接销毁线程,而是给工作着线程发生任务队列非空的条件变量,让工作者线程主动退出,工作者线程是在获取线程池锁后等待条件变量,但是在等待到条件变量,线程退出之前,没有释放线程池锁,导致其他工作者线程永远等待线程池锁释放,最终造成程序卡死。
void* worker(void* arg) {
ThreadPool *pool = (ThreadPool *)arg;
while(1) {
pthread_mutex_lock(&pool->mutexPool);
while(pool->taskNum == 0 && pool->shutdown == 0) {
pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);
if(pool->exitNum > 0) {
// printf("worker exit num: %d %lu\r\n", pool->exitNum, pthread_self());
pool->exitNum--;
if(pool->liveNum > pool->minNum) {
pool->liveNum--;
// 出现bug是因为没有这一句
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
}
}
// printf("running %lu\r\n", pthread_self());
if(pool->shutdown) {
// printf("shoutdown %lu\r\n", pthread_self());
pthread_mutex_unlock(&pool->mutexPool);
threadExit(pool);
}
Task t = pool->tq[pool->taskFront];
pool->taskFront = (pool->taskFront + 1) % pool->taskCapacity;
pool->taskNum--;
pthread_cond_signal(&pool->notFull);
pthread_mutex_unlock(&pool->mutexPool);
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum++;
pthread_mutex_unlock(&pool->mutexBusy);
printf("%lu start\r\n", pthread_self());
t.function(t.arg);
printf("%lu end\r\n", pthread_self());
free(t.arg);
t.arg = NULL;
pthread_mutex_lock(&pool->mutexBusy);
pool->busyNum--;
pthread_mutex_unlock(&pool->mutexBusy);
}
}
解决:
在线程退出前释放锁