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

C++线程详解

1.Linux线程的概念

我们在写C/C++程序的时候,都是重main函数开始执行的,从上而下,只有一条执行路线。如果我们想要同时干两件事或者多件事,这次我们就需要线程,分出一个执行分支来执行任务。

•在一个程序里的一个执行路线叫做线程

•线程在进程内部运⾏,本质是在进程地址空间内运行

•有些任务场景需要 “等待 IO”, 为了让等待 IO 的时间能够去做⼀些其他的工作, 也需要用到并发编程。其次,虽然多进程也能实现 并发编程, 但是线程比进程更轻量.

2.创建线程

在Linux上,没有提供专门的线程,而是提供了轻量化进程,为了满足用户的遍历,在语言层实现了封装,在pthread的库中提供了专门的调用接口。

2-1 认识pthread_create函数

#include <pthread.h>int pthread_create(pthread_t *thread,          // 指向线程标识符的指针const pthread_attr_t *attr, // 线程属性(通常设为 NULL 使用默认属性)void *(*start_routine)(void*), // 线程执行的函数void *arg                   // 传递给线程函数的参数
);

参数说明

  1. thread
    指向 pthread_t 类型的变量,用于存储新创建线程的标识符。

  2. attr
    指向 pthread_attr_t 类型的结构体,用于设置线程的属性(如栈大小、调度策略等)。若为 NULL,则使用默认属性。

  3. start_routine
    线程启动后要执行的函数,必须符合 void* (*)(void*) 的函数签名,即接受一个 void* 类型的参数并返回 void*

  4. arg
    传递给 start_routine 的参数,类型为 void*。若无需传递参数,可设为 NULL

返回值

  • 成功:返回 0
  • 失败:返回错误码(如 EAGAINEINVAL 等),且 *thread 的值未定义。

2-2 案例实现

//新线程执行流
void* threadrun(void* args)
{//这里的args拿到的就是创建线程时传递的地址,类型是无符号类型,在使用时需要自己进行强转std::string name = (const char*)args;while(1){std::cout << "我是新线程:name" << name << std::endl;sleep(1);}return nullptr;
}//main执行流
int main()
{pthread_t tid;//调用接口创建线程pthread_create(&tid, nullptr, threadrun, (void*)"thread -1");while(1){std::cout << "我是主线程..." << std::endl;sleep(1);}return 0;}//运行结果
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1
我是主线程...
我是新线程:namethread -1

可以看到上述有两个while死循环,分别属于两个执行流,同时进行输出。

3.线程等待

主线程也就是main执行流有时需要等待新线程完成相应的任务,并回收新线程的资源。这个时候就需要线程等待(类似于进程等待)

3-1 线程等待函数

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);
  • 功能:阻塞当前线程,直到指定的 thread 线程终止。
  • 参数
    • thread:目标线程的标识符(由 pthread_create() 返回)。
    • retval:指向 void* 的指针,用于存储线程函数的返回值(即 start_routine 的返回值)。若无需获取返回值,可设为 NULL
  • 返回值
    • 成功:返回 0
    • 失败:返回错误码(如 EDEADLKESRCH 等)。

3-2 实现案例

void* routine(void* args)
{std::string name = (char*)args;int cut = 5;while(cut--){sleep(1);std::cout << "我是一个线程" << Formata(pthread_self()) << cut << std::endl;}static int a = 10;return (void*)(&a);
}//实现一个线程等待的案例
int main()
{pthread_t tid;int n = pthread_create(&tid, nullptr, routine, (void*)"thread -1");void* a = nullptr;pthread_join(tid,&a);std::cout << *(int*)a << std::endl;}

这里的新线程在内部创建了一个静态变量a,并返回了a的地址。主线程(main)进行线程等待,回收新线程。拿到返回值a的地址。

4. 线程分离

在新线程结束的时候,我们需要等待主线程回收新线程,如果我们不想等待新线程,我们可以把新线程分离出来,这样在其终止后,资源会自动释放,无需其他线程等待。

4-1线程分离函数

#include <pthread.h>int pthread_detach(pthread_t thread);
  • 功能:将线程标记为 “分离” 状态,使其终止后资源自动释放,无需其他线程调用 pthread_join()
  • 参数
    • thread:目标线程的标识符。
  • 返回值
    • 成功:返回 0
    • 失败:返回错误码(如 ESRCH)。

4-2 实现案例

主线程和新线程都可以设置线程分离

void* thread(void* args)
{// pthread_detach(pthread_self());sleep(10);}int main()
{pthread_t tid;pthread_create(&tid, nullptr, thread, (void*)"threadtest");pthread_detach(tid);while(1){std::cout << "我是主线程" << std::endl;}
}

5.线程退出

#include <pthread.h>
void pthread_exit(void *retval);
  • 功能:立即终止当前线程,并通过 retval 传递返回值。

http://www.xdnf.cn/news/16533.html

相关文章:

  • C++11 std::function 详解:通用多态函数包装器
  • 从0开始学习R语言--Day62--RE插补
  • 【ssh】ubuntu服务器+本地windows主机,使用密钥对进行ssh链接
  • Linux常用基础命令
  • 反射核心:invoke与setAccessible方法详解
  • Git 从入门到精通
  • linux命令ps的实际应用
  • SQL注入SQLi-LABS 靶场less26-30详细通关攻略
  • 深入解析Java元注解与运行时处理
  • ​第七篇:Python数据库编程与ORM实践
  • 前缀和-974.和可被k整除的子数组-力扣(LeetCode)
  • [mcp: JSON-RPC 2.0 规范]
  • 机器学习之线性回归——小白教学
  • LRU(Least Recently Used)原理及算法实现
  • 最新优茗导航系统源码/全开源版本/精美UI/带后台/附教程
  • BreachForums 黑客论坛强势回归
  • sqLite 数据库 (2):如何复制一张表,事务,聚合函数,分组加过滤,列约束,多表查询,视图,触发器与日志管理,创建索引
  • JAVA_TWENTY—ONE_单元测试+注解+反射
  • 学习Python中Selenium模块的基本用法(3:下载浏览器驱动续)
  • Seq2Seq学习笔记
  • 前端优化之虚拟列表实现指南:从库集成到手动开发
  • 嵌入式学习日志————TIM定时中断之定时器定时中断
  • Python算法实战:从排序到B+树全解析
  • 算法精讲:二分查找(一)—— 基础原理与实现
  • 自学嵌入式 day37 HTML
  • 信号上升沿时间与频谱分量的关系
  • FastAPI后台任务:异步魔法还是同步噩梦?
  • Simulink建模-Three-Phase V-I Measurement 模块详解
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现各种食物的类型检测识别(C#代码UI界面版)
  • react 的 useTransition 、useDeferredValue