线程之多线程函数
一,线程的概念
进程是操作系统分配的最小单位,而线程是进程内部的执行单元,是操作系统CPU调度的最小单位,简单来说就是一个进程可以有多个线程。
二,与进程对比
| 维度 | 进程 | 线程 |
|---|---|---|
| 资源 | 独立的地址空间、文件描述符等系统资源 | 共享所属进程的地址空间和资源 |
| 调度 | 进程是资源分配的基本单位 | 线程是 CPU 调度的基本单位 |
| 开销 | 创建 / 切换开销大(需复制页表等) | 创建 / 切换开销小(共享资源,仅保存少量寄存器) |
| 通信 | 需通过 IPC(管道、消息队列、共享内存) | 可直接读写共享变量,通信简单但需同步 |
| 健壮性 | 进程崩溃不影响其他进程 | 一个线程崩溃会导致整个进程退出 |
应用场景:
- 进程适用于资源隔离要求高,稳定性优先的场景,如Web服务器的工作进程,数据库的多进程架构
- 线程适用于高并发,计算密集型任务,如Web服务器的线程池,GUI程序的后台任务处理
三,多线程相关函数
1.前置条件
- 头文件:
#include <pthread.h>- 编译时必须加链接库参数:
gcc main.c -o main -lpthread- 所有pthread函数成功返回0,失败返回错误码
2.创建线程:pthread_create
作用:创建一个新线程,让它开始指定的函数,参数结构如下:
int pthread_create( pthread_t *thread, // 输出:存储新线程的ID const pthread_attr_t *attr, // 线程属性(默认填NULL) void *(*start_routine)(void *), // 线程要执行的函数指针,也称入口函数 void *arg // 传递给线程函数的参数(无参数填NULL) );3.等待线程结束:pthread_join
作用:阻塞等待指定线程执行完毕,并回收线程资源(避免内存泄漏),参数结构如下:
int pthread_join( pthread_t thread, // 要等待的线程ID void **retval // 接收线程的返回值(不接收填NULL) );4.线程主动退出:pthread_exit
线程自己调用,主动终止运行,可以带返回值,结构如下:
void pthread_exit(void *retval); // retval:线程返回值ps:即使主线程退出,子线程也能继续执行
5.获取线程自身线程id:pthread_self
线程获取自己的id,类似于进程的getpid,结构如下:
pthread_t pthread_self(void);线程属性相关函数
6.分离线程:pthread_detach
将线程设置为分离态,分离态下线程退出后系统自动回收其资源,无需调用pthread_join
结构如下:
int pthread_detach(pthread_t thread);7.初始化线程属性:pthread_attr_init
初始化线程属性对象,将属性设置为默认值,结构如下:
int pthread_attr_init(pthread_attr_t *attr);//attr需要被初始化的线程属性对象8.设置线程属性对象的分离状态:pthread_attr_setdetachstate
用于设置线程属性对象的分离状态,结构如下:
int pthread_attr_setdetachstate( pthread_attr_t *attr, //设置分离状态的线程属性对象 int detachstate //用于指定线程的分离状态 //PTHREAD_CREATE_JOINABLE :表示将线程设置为结合态 //PTHREAD_CREATE_DETACHED :表示将线程设置为分离态 );9.销毁线程属性:pthread_attr_destroy
销毁属性对象占用的资源,与初始化函数成对使用,结构如下:
int pthread_attr_destroy(pthread_attr_t *attr);ps:销毁后的属性可以重新初始化,不影响已创建的线程。
线程取消相关函数
10.请求取消指定线程:pthread_cancel
向指定线程发送取消请求,它只是一个请求,调用成功也只是代表请求已提交,不代表线程已经终止了,结构如下:
int pthread_cancel(pthread_t thread);11.设置取消状态:pthread_setcancelstate
设置调用线程自身的取消状态,即是否允许响应pthread_cancel的请求,参数:
| 参数 | 说明 |
|---|---|
state | 新的取消状态,二选一:
|
oldstate | 输出参数,存储修改前的旧状态(传NULL表示不需要保存旧状态) |
int pthread_setcancelstate(int state, int *oldstate);12.设置取消类型:pthread_setcanceltype
设置调用线程自身的取消类型,仅在取消状态为PTHREAD_CANCEL_ENABLE时生效,决定线程收到请求后何时终止,参数:
| 参数 | 说明 |
|---|---|
type | 新的取消类型,二选一:
|
oldtype | 输出参数,存储修改前的旧类型(传NULL表示不需要保存旧类型) |
int pthread_setcanceltype(int type, int *oldtype);13.取消函数的示例代码
//请求取消指定线程 /* 请求取消指定线程取决于线程的取消状态和取消类型 取消状态:可取消和不可取消 取消类型:延时取消和可被立即取消(异步取消) 三种情况: 1. 可取消的线程+延时取消 2. 可取消的线程+可被立即取消 3. 不可取消的线程 */ #include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> #include <stdlib.h> //情况1:可取消的线程+延时取消 void *thread1(void *arg) { //设置线程1取消状态和取消类型 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL); while(1) { //结果:不会每隔1秒打印一次线程1正在运行... //因为线程1收到请求取消信号,线程1会在取消点进行取消 printf("线程1正在运行...\n"); sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } //情况2:可取消的线程+可被立即取消 void *thread2(void *arg) { //设置线程2取消状态和取消类型 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); while(1) { //因为设置为了立即取消,所以线程2会立即取消 //所以将sleep注释之后无法显示 printf("线程2正在运行...\n"); //sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } //情况3:不可取消的线程 void *thread3(void *arg) { //设置线程3取消状态为不可取消 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL); while(1) { //因为设置为了不可取消,所以线程3不会取消 printf("线程3正在运行...\n"); sleep(1); } return NULL;//注意:此处返回值不可以为丢,没有实际意义 } int main(int argc,const char *argv[]) { //情况1:可取消的线程+延时取消 pthread_t tid1 = 0; int ret = pthread_create(&tid1,NULL,thread1,NULL); if(ret != 0) { fprintf(stderr,"创建线程1失败,错误信息:%s\n",strerror(ret)); return -1; } printf("创建线程1成功,线程1ID:%ld\n",tid1); //情况2:可取消的线程+可被立即取消 pthread_t tid2 = 0; int ret2 = pthread_create(&tid2,NULL,thread2,NULL); if(ret2 != 0) { fprintf(stderr,"创建线程2失败,错误信息:%s\n",strerror(ret2)); return -1; } printf("创建线程2成功,线程2ID:%ld\n",tid2); //情况3:不可取消的线程 pthread_t tid3 = 0; int ret3 = pthread_create(&tid3,NULL,thread3,NULL); if(ret3 != 0) { fprintf(stderr,"创建线程3失败,错误信息:%s\n",strerror(ret3)); return -1; } printf("创建线程3成功,线程3ID:%ld\n",tid3); //请求取消指定的线程1 int ret_cancel = pthread_cancel(tid1); //只能说明请求取消成功,不能说明会被立即取消 if(ret_cancel != 0) { fprintf(stderr,"请求取消线程1失败,错误信息:%s\n",strerror(ret_cancel)); return -1; } printf("请求取消线程1成功\n"); //请求取消指定的线程2 int ret_cancel2 = pthread_cancel(tid2); if(ret_cancel2 != 0) { fprintf(stderr,"请求取消线程2失败,错误信息:%s\n",strerror(ret_cancel2)); return -1; } printf("请求取消线程2成功\n"); //请求取消指定的线程3 int ret_cancel3 = pthread_cancel(tid3); if(ret_cancel3 != 0) { fprintf(stderr,"请求取消线程3失败,错误信息:%s\n",strerror(ret_cancel3)); return -1; } printf("请求取消线程3成功\n"); //阻塞等待线程退出 pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); return 0; }