一、多线程
进程:程序在系统中执行和资源分配的基本单位,程序加载到内存中运行。
线程:
轻量级的进程
进程内的基本的调度单位
共享进程的内存空间,其他的资源
线程的优点:
线程占用的系统的资源比进程要少的多;
线程的创建要比进程的创建要简单的多;
线程的创建的速度比进程的创建的速度要快很多;
线程的切换的速度要比进程的切换的速度快的多
缺点:线程一死俱死
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的接口:
线程也有一个关键字 ---------pthread
pthread_create():创建一个线程
函数的头文件:pthread.h
函数的原型:
int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg);
函数的参数:
pthread_t *thread:线程的id号,类似于进程的进程号
const pthread_attr_t *attr:线程的属性(分离属性、绑定属性), 一般填写NULL即可
void *(*start_routine)(void *):线程要做的事情,线程的实现函数
eg:void *myfunc(void * arg)
void *arg:传给线程的实现函数的参数 ,一般为0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
注意:
多线程的调度的次序跟进程的调度次序类似,无法确定谁先执行,谁后执行。
在编译用到线程相关的函数的时候,要在编译命令的后边加上 库的引用 -lpthread
eg:gcc app.c -o app -lpthread
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_self():获取自己的线程的pid号,格式控制符%ld
头文件:同上
函数的原型:phread_t pthread_self(void)
函数的参数:无
函数的返回值:成功返回 线程的pid号
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
进程的退出有专门的函数
pthread_exit():线程的正常退出
头文件:同上
函数的原型: void pthread_exit(void *retval)
函数的参数:线程退出的状态,一般写NULL
函数的返回值:无
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_join():等待一个线程结束,类似于进程里wait/waitpid
头文件:同上
函数的原型:int pthread_join(pthread_t thread,void**retval)
函数的参数:
pthread_t thread:要等待的线程号
void**retval:线程返回的状态值,一般写NULL
函数的返回值:成功返回 0 失败返回 error
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_cancel():取消一个线程的执行,无论被取消的线程的状态如何都强制取消,取消有一定的时间,在要取消的线程里面加个sleep
头文件:同上
函数的原型:int pthread_cancel(pthread_t thread);
函数的参数:pthread_t thread:线程号
函数的返回值:成功返回 0 失败返回 非零值
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
线程的钩子函数,用来清理线程的
pthread_cleanup_push();pthread_cleanup_pop(): 退出清零函数
pthread_cleanup_push()带有一个"{",而pthread_cleanup_pop()带有一个"}",因此这两个函数必须成对出现,且必须位于程序的同一级别的代码段中才能通过编译。一般中间可以有其他语句出现,只要不影响“{}”就行。
头文件:同上
函数原型:void pthread_cleanup_push(void (*routine)(void*), void *arg);
void pthread_cleanup_pop(int execute);
参数:
void (*routine)(void*):清理的回调函数
eg:void mufunc(void *arg);
void *arg:传递给清理函数的参数,一般为NULL
execute:显示回调函数是否使能
0:表示不调用
1:非零,表示调用
二、线程的同步与互斥
如果使用同步和互斥一定所有的线程都要遵循这个操作,否则就没有意义。
1.作用:实现对资源的保护,以及独占
2.手段:互斥锁、条件变量、信号灯
3.互斥锁:本质就是一个结构体变量,作用就是保护临界资源,操作有两个,加锁和解锁
4.互斥锁的流程
初始化:pthread_mutex_init
上锁:pthread_mutex_lock
解锁:pthread_mutex_unlock
销毁锁:pthread_mutex_destroy
注意:使用锁的时候 必须要安装相关的库文件
apt-get install manpages-posix-dev
5.互斥锁的函数
int pthread_mutex_init():初始化一个互斥锁(动态创建)
头文件:pthread.h
函数原型:
int pthread_mutex_init (pthread_mutex_t *mutex,const pthread_mutexattr_t *__mutexattr)
参数:
pthread_mutex_t *mutex:互斥锁的结构体的指针
const pthread_mutexattr_t *__mutexattr:锁的类型
NULL:创建快速互斥锁
返回值:成功,0 失败,error
静态创建:
pthread_mutex_t lock =PTHREAD_MUTEX_INITIALIZER;
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int pthread_mutex_lock();
int pthread_mutex_trylock():互斥锁的加锁
头文件:pthread.h
函数原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞的加锁,当申请到锁,则返回,申请不到则阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞的申请锁,当申请到锁的时候马上返回,申请不到也马上返回,成功申请到锁 返回0,失败 返回非零
参数:pthread_mutex_t *mutex:互斥锁的结构体的指针
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_mutex_unlock():互斥锁的解锁
头文件:pthread.h
函数的原型:int pthread_mutex_unlock(pthread_mutex_t *mutex);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_mutex_destroy():销毁锁
头文件:pthread.h
函数的原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
6.条件变量
使用方法和锁差不多
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_cond_init():(动态创建)条件变量的结构体的初始化
函数的原型:
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
函数的参数:
pthread_cond_t *restrict cond:条件变量结构体
const pthread_condattr_t *restrict attr:固定填NULL
静态创建
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_cond_wait():满足不了条件则阻塞线程
函数的原型:
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
函数的参数:
pthread_cond_t *restrict cond:条件变量的结构体指针
pthread_mutex_t *restrict mutex:互斥锁的结构体的指针
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_cond_signal():解除线程的阻塞
函数的原型:int pthread_cond_signal(pthread_cond_t *cond);
函数的参数:pthread_cond_t *cond:条件变量的结构体
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
pthread_cond_destroy():销毁条件变量
函数原型:int pthread_cond_destroy(pthread_cond_t *cond);
7.信号灯
信号量本质上就是一个能进行加或者是减操作的一个数,信号灯几乎和进程中信号量一样(但还是不同),当这个数减到0,就表示资源没有了,陷入阻塞。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
sem_init():信号灯的创建
头文件:semaphore.h
原型: int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem_t *sem:信号灯的核心结构体
int pshared:固定填0
unsigned int value:信号灯的初值
返回值:成功返回 0 失败返回 非零
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
sem_wait():p操作,消耗一个信号灯
头文件:semaphore.h
原型:
int sem_wait(sem_t *sem);---阻塞
当去申请一个信号量的时候,假如能申请到,则返回,假如申请不到,则阻塞。
int sem_trywait(sem_t *sem);--非阻塞
当去申请一个信号量的时候,无论能不能申请成功都返回,我们可以通过他的返回值来判断申请成功或者是失败。
参数:sem_t *sem, :信号灯的核心结构体
返回值:成功返回 0 失败返回 非零
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
sem_post():v操作,释放一个信号灯
头文件:semaphore.h
原型:int sem_post(sem_t *sem);
参数:sem_t *sem, :信号灯的核心结构体
返回值:成功返回 0 失败返回 非零
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
sem_destroy():销毁一个信号灯
头文件:semaphore.h
原型:int sem_destroy(sem_t *sem);
参数:sem_t *sem, :信号灯的核心结构体
8.线程间的通讯
1)直接共享进程的资源(利用全局变量)
2)信号,pthread_kill();
pthread_kill():向某个线程发送一个信号
头文件:signal.h
原型:int pthread_kill(pthread_t pd,int sig)
参数:
pthread_t pd:线程id
int sig:发送的信号
函数的返回值:成功返回 0 失败返回 非零