当前位置: 首页 > news >正文

线程基本API

线程的概念

在这里插入图片描述
进程是分配资源的最小单位,所有线程都共享一套内存,状态是独立的


基本接口


1.线程的创建

函数原型

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine)(void *),void *arg
);

参数解释

thread:新线程的TID
attr:线程属性,若创建标准线程则该参数可设置为NULL
start_routine:线程函数
arg:线程函数的参数

示例

// simpleThread.c
#include <pthread.h>void *doSomething(void *arg)//arg为返回值
{// ...
}int main()
{// 创建一条线程,并让其执行函数 doSomething()pthread_t tid;pthread_create(&tid, NULL, doSomething, NULL);// ...
}

线程的各种接口单独放在线程库中,因此在编译带线程的代码时,必须要指定链接线程库phread,如下:

gec@ubuntu:~$ gcc simpleThread.c -o simpleThread -lpthread 

注意

由于线程函数的并发性,在线程中访问共享资源需要特别小心,因为这些共享资源会被多个线程争抢,形成“竞态”。


2.线程的退出

函数原型

#include <pthread.h>void pthread_exit(void *retval);

注意此函数与exit的区别:
pthread_exit(): 退出当前线程
exit(): 退出当前进程(即退出进程中的所有线程)
主线程退出后,其余线程可以继续运行


3.线程的接合

与进程类似,线程退出之后不会立即释放其所占有的系统资源,而会成为一个僵尸线程,可使用 pthread_join() 来释放僵尸线程的资源,并可获得其退出时返回的退出值,该接口函数被称为线程的接合函数:
函数原型

#include <pthread.h>int pthread_join(pthread_t tid, void **val);

参数说明
pthread_t tid:线程的ID
val:线程的返回值 注意:线程返回值是一个指针,其中指向的内容必须没有被自动释放,例如局部变量
函数说明

若指定tid的线程尚未退出,那么该函数将持续阻塞。
若只想阻塞等待指定线程tid退出,而不想要其退出值,那么val可置为NULL。
若指定tid的线程处于分离状态,或不存在,则该函数会出错返回。


4.其他API


获取线程TID

#include <pthread.h>pthread_t pthread_self(void);

TID仅限于进程内部的线程间有效


线程的分离与联合

在这里插入图片描述
注意
分离时机:pthread_detach 可以在线程创建后立即调用,也可以在线程运行期间调用。但通常建议在线程创建后尽快分离。
线程终止:分离线程的终止状态无法被其他线程获取,因此如果需要线程的返回值,不能使用分离。
资源泄漏:如果线程既未被分离,也未被 pthread_join,可能会导致资源泄漏(僵尸线程)。
错误码:只要是pthread开头的函数,返回值都为独立的错误码,而不是直接修改全局变量errno

示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>//将错误码转换为字符串必须使用该头文件void * doSomething(void *)
{//sleep(2);pthread_detach(pthread_self());//分离线程,让资源自动释放printf("子线程的线程号:%lu\n", pthread_self());//获得当前线程TIDchar * return_val = "Create Thread Sussess\n";pthread_exit(return_val);//返回程序函数执行结束需要返回的值
}int main(void)
{pthread_t tid;pthread_create(&tid, NULL, doSomething, NULL);//创建一条子线程printf("主线程的线程号:%lu\n", pthread_self());//获取当前线程的TIDsleep(2);void * return_val;int err = pthread_join(tid, &return_val);//获取返回值printf("返回的错误为:%s\n", strerror(err));printf("子线程返回值为:%s\n", (char *)return_val);return 0;}

运行结果
在这里插入图片描述


线程的单例

希望某个函数只被严格执行一次,并且需要在程序一开始进行执行,由于线程的并发特性,我们无法预先知晓哪条线程会对信号量进行初始化,于是就希望有一种只执行一遍的函数单例,可以被众多的并发线程放心去调用。
函数接口

#include <pthread.h>// 函数单例控制变量
pthread_once_t once_control = PTHREAD_ONCE_INIT;// 函数单例启动接口
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));

参数说明

once_control是一种特殊的变量,用来关联某个函数单例,被关联的函数单例只会被执行一遍。
init_routine函数指针指向的函数就是只执行一遍的函数单例。

示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>#include <pthread.h>// 函数单例控制变量
pthread_once_t once_control = PTHREAD_ONCE_INIT;void init_routine(void)
{printf("我会被严格执行一遍。\n");
}void *f(void *arg __attribute__((unused)))
{pthread_once(&once_control, init_routine);pthread_exit(NULL);
}int main()
{pthread_t tid;for(int i=0; i<20; i++)pthread_create(&tid, NULL, f, NULL);pthread_exit(NULL);
}

线程的取消

函数API

#include <pthread.h>int pthread_cancel(pthread_t thread);//取消已有的进程

返回值

成功时返回0,失败时返回错误码。

取消状态
可以设置线程是否接收取消,若不接收取消则取消信号无效,接收取消会在取消点进行线程的取消 通过以下API进行设置

int pthread_setcancelstate(int state, int *oldstate);//设置取消状态
int pthread_setcanceltype(int type, int *oldtype);//设置取消类型

取消状态:决定线程是否响应取消请求。
PTHREAD_CANCEL_ENABLE:线程可以响应取消请求(默认)。
PTHREAD_CANCEL_DISABLE:线程忽略取消请求。
取消类型:决定线程如何响应取消请求。
PTHREAD_CANCEL_DEFERRED:线程在下一个取消点(Cancellation Point)检查取消请求(默认)。
PTHREAD_CANCEL_ASYNCHRONOUS:线程可能在任何时间点被取消(不推荐,可能导致资源泄漏)。

清理处理

线程取消时可能需要释放资源(如内存、文件描述符等)。可以通过线程清理处理程序(Thread Cleanup Handlers)实现。清理处理程序是注册的函数,在线程取消或调用pthread_exit时执行。

@ void (*routine)(void *) : 要注册的函数指针
@ void *arg : 传给清理函数的参数
@ int execute :调用时传入非零参数会执行回调函数,传入零参数仅清理而不执行。
void pthread_cleanup_push(void (*routine)(void *), void *arg);//注册清理函数
void pthread_cleanup_pop(int execute);

线程属性

线程有许多属性,可以在终端中查看跟线程属性相关的函数:敲入如下命令后连续按两下tab键
在这里插入图片描述
线程属性的使用

#include <pthread.h>int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
  1. 定义且初始化属性变量 attr
  2. 将所需的属性,加入 attr 中
  3. 使用 attr 启动线程
  4. 销毁 attr

示例

// 初始化属性变量,并将分离属性添加进去pthread_attr_t attr;//创建属性变量pthread_attr_init(&attr);//初始化属性pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置属性pthread_attr_destory(&attr);//销毁属性
http://www.dtcms.com/a/336156.html

相关文章:

  • 输入坐标移动
  • 在线编程题目之小试牛刀
  • 多线程—飞机大战(加入排行榜功能版本)
  • 数字化转型成功案例:赋能供应链运输成本精细化管理
  • 网络编程3(网络层,数据链路层)
  • 批次号规则
  • Vue中v-show与v-if的区别
  • 【AI论文】序曲(PRELUDE):一项旨在考察对长文本语境进行全局理解与推理能力的基准测试
  • C语言私人学习笔记分享
  • STM32单片机学习日记
  • 第四章:大模型(LLM)】06.langchain原理-(7)LangChain 输出解析器(Output Parser)
  • 模型提取的相关经验
  • 库制作与原理(下)
  • 端到端测试:复杂系统的终极体检术
  • 【C2000】德州仪器C2000产品开发板的原理图如何找到?
  • 反向代理、负载均衡器与API网关选型决策
  • 《MutationObserver深度解构:重塑自动化视觉回归测试的底层逻辑》
  • B站 韩顺平 笔记 (Day 21)
  • [python学习记录2]变量
  • 【Unity3D实例-功能-拔枪】角色拔枪(二)分割上身和下身
  • vue封装请求拦截器 响应拦截器
  • 定时器输出PWM波配置(呼吸灯)
  • 平行双目视觉-动手学计算机视觉18
  • C++ Building Blocks 构建块 Or 构件块
  • SVN客户端下载与安装
  • 「数据获取」《中国教育统计年鉴》(1949-2023)(获取方式看绑定的资源)
  • 【嵌入式基础知识梳理#11】Modbus-RTU工业总线协议
  • Spring IOC 学习笔记
  • Canny边缘检测
  • Python异步编程实战:爬虫案例