Linux——线程

devtools/2025/4/1 2:07:18/

Linux——线程

目录

一、线程

1.1 创建一个线程

1.2 主函数等待线程结束pthread_join

为什么输出是乱序的


一、线程

线程:进程内部的一条执行路径

进程:一个正在运行的程序

进程相当于工厂车间,线程就是车间里的许多工人

1.1 创建一个线程

#include <stdio.h>      // 包含标准输入输出头文件
#include <string.h>     // 包含字符串处理头文件
#include <pthread.h>    // 包含POSIX线程库头文件
#include <unistd.h>     // 包含POSIX操作系统API头文件,用于sleep函数// 定义一个线程函数
void* fun(void* arg)
{for(int i = 0; i < 5; i++){printf("fun run\n");sleep(1); // 线程休眠1秒}
}int main()
{pthread_t id; // 定义一个线程标识符// 创建一个线程,执行fun函数pthread_create(&id, NULL, fun, NULL);for(int i = 0; i < 5; i++){printf("main run\n");sleep(1); // 主线程休眠1秒}
}
  • pthread_t id;:定义一个线程标识符id,用于跟踪创建的线程。

  • pthread_create(&id, NULL, fun, NULL);:创建一个新线程,执行fun函数。第一个参数是线程标识符的地址,第二个参数是线程属性(这里使用NULL表示使用默认属性),第三个参数是线程函数,第四个参数是传递给线程函数的参数(这里使用NULL)。

  • 在主线程中,使用一个循环打印5次"main run",每次打印后休眠1秒。

  • pthread_join(id, NULL);:等待由id标识的线程结束。这确保主线程在子线程结束后才继续执行。

去掉sleep休眠运行时会发生:

因为线程结束了不会影响主线程,但主线程main结束了,线程fun也会直接结束

1.2 主函数等待线程结束pthread_join

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>void* fun(void* arg)
{for(int i = 0; i < 5; i++ ){printf("fun run\n");sleep(1);}pthread_exit("fun finish");//线程结束并返回一个字符串
}
int main()
{pthread_t id;pthread_create(&id,NULL,fun,NULL);//创建线程for(int i = 0; i < 2; i++ ){printf("main run\n");sleep(1);}char* s = NULL;pthread_join(id,(void**)&s);//阻塞,等待线程结束,并获取返回值printf("s=%s\n",s );//打印线程返回值exit(0);
}

pthread_exit:用于终止一个线程的执行,并可以选择性地返回一个值给等待该线程结束的其他线程。这个函数是线程的“退出点”,

pthread_join :

int pthread_join(pthread_t thread, void** retval);
  • pthread_t thread:目标线程的ID,标识要等待的线程。这个ID是在调用pthread_create时返回的。

  • void** retval:一个指向指针的指针,用于存储目标线程的返回值。如果目标线程调用了pthread_exit并返回了一个值,这个值将被存储在*retval中。如果不需要获取返回值,可以传递NULL

  • pthread_join通常用于以下场景:

  • 主线程等待子线程结束:在多线程程序中,主线程可能需要等待子线程完成任务后再继续执行。

  • 获取线程返回值:如果线程需要返回一个值给主线程或其他线程,可以通过pthread_join获取这个值。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>// 线程函数
void* fun(void* arg) {int *p = (int*)arg;  // 将void*类型的参数转换为int*类型int index = *p;     // 获取线程的索引值printf("index=%d\n", index);  // 打印线程索引pthread_exit(NULL);  // 线程结束,返回NULL
}int main() {pthread_t ids[5];  // 定义一个数组,用于存储5个线程的IDint i = 0;// 创建5个线程for (; i < 5; i++) {pthread_create(&ids[i], NULL, fun, &i);  // 创建线程,并将i的地址传递给线程函数}// 等待5个线程结束for (i = 0; i < 5; i++) {pthread_join(ids[i], NULL);  // 等待线程结束}exit(0);  // 正常退出程序
}

 

创建了5个线程,每个线程都打印了一个索引值。然而,输出的顺序并不是按照线程创建的顺序(0到4),而是出现了一些乱序的情况。这种情况发生的原因主要与线程调度有关。每次运行程序时,由于线程调度的不确定性,输出的顺序可能会有所不同。

线程调度是由操作系统负责的,它决定哪个线程在什么时候运行。在多线程程序中,线程的执行顺序可能会因为操作系统的调度策略而变得不确定。

为什么输出是乱序的

  1. 并发执行:当多个线程被创建后,它们可能同时处于就绪状态,等待CPU时间片来执行。操作系统的线程调度器会根据一定的策略(如优先级、时间片轮转等)来决定哪个线程获得CPU时间片,从而得以执行。

  2. 时间片轮转:在时间片轮转调度算法中,每个线程会被分配一个时间片,即允许它运行的时间。当一个线程的时间片用完后,如果它还没有完成,它会被放到就绪队列的末尾,等待下一次调度。

  3. 线程切换:操作系统会在不同的线程之间快速切换,使得每个线程都能获得执行的机会。这种快速切换可能会在很短的时间内发生,从而给用户一种多个线程同时运行的错觉。


http://www.ppmy.cn/devtools/170903.html

相关文章

LeetCode 每日一题 2025/3/17-2025/3/23

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 3/17 1963. 使字符串平衡的最小交换次数3/18 2614. 对角线上的质数3/19 2610. 转换二维数组3/20 2612. 最少翻转操作数3/21 2680. 最大或值3/22 2643. 一最多的行3/23 2116…

第十六届蓝桥杯模拟二

由硬件框图可以知道我们要配置LED 和按键 一.LED 先配置LED的八个引脚为GPIO_OutPut,锁存器PD2也是,然后都设置为起始高电平,生成代码时还要去解决引脚冲突问题 二.按键 按键配置,由原理图按键所对引脚要GPIO_Input 生成代码,在文件夹中添加code文件夹,code中添加fun.…

代码随想录算法训练营第十五天|右旋字符串

文档讲解&#xff1a;代码随想录 难度&#xff1a;easy 附&#xff1a;冲 passion&#xff01;&#xff01;&#xff01;passion&#xff01;&#xff01;&#xff01;passion&#xff01;&#xff01;&#xff01; 卡码网题目链接(opens new window) 字符串的右旋转操作是把…

Python 单例模式的 5 种实现方式:深入解析与最佳实践

单例模式&#xff08;Singleton Pattern&#xff09;是一种经典的设计模式&#xff0c;其核心思想是确保一个类在整个程序运行期间只有一个实例&#xff0c;并提供一个全局访问点。这种模式在许多场景中非常有用&#xff0c;例如全局配置管理、日志记录器、数据库连接池等。 然…

Java基础编程练习第34题-正则表达式

在Java里&#xff0c;正则表达式是一种强大的文本处理工具&#xff0c;它可以用于字符串的搜索、替换、分割和校验等操作。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。Java通过java.util.regex包提供了对正则表达式的支持。 以下是正则表达式在Jav…

前端面试:[React] useRef 是如何实现的?

useRef 是 React 中一个非常有用的 Hook&#xff0c;它用于在组件中持久存储可变的值而不会引起重新渲染。理解 useRef 的实现原理对于更高效地使用它非常重要。以下是 useRef 的实现原理和使用场景的详细说明。 一、useRef Hook 的基本概念 持久引用&#xff1a;useRef 返回…

如何制作一个手机用的电动3D扫描转盘

这个项目里&#xff0c;作者会教你怎么做一个简单的电动3D扫描转盘&#xff0c;主要是给手机用的。整个装置分为三个部分&#xff1a;顶板、齿轮板和底座。顶板是个固定的平台&#xff0c;用来放置你要扫描的物体。 中间的齿轮板是整个装置的核心&#xff0c;它有一个隐藏的齿轮…

HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错:Error message:is not callable

HarmonyOS鸿蒙开发 BuilderParam在父组件的Builder的点击事件报错&#xff1a;Error message:is not callable 最近在鸿蒙开发过程中&#xff0c;UI做好了&#xff0c;根据列表item进行点击跳转&#xff0c;报错了 报错信息如下 Error message:is not callable Stacktrace:at…