linux_线程基础函数-pthread_self函数-pthread_create函数-pthread_exit函数-pthread_join函数

news/2025/1/31 8:47:33/

接上一篇:linux_线程概念-内核线程实现原理-线程共享资源-线程优缺点

  今天来分享线程的代码函数了,主要是获得线程ID、创建线程函数、线程退出函数、等待线程结束函数,以及分享这些函数的例子,话不多说,开始上菜:

此博主在CSDN发布的文章目录:我的CSDN目录,作为博主在CSDN上发布的文章类型导读

目录

  • 1.pthread_self函数
  • 2.pthread_create函数
    • 2.1.线程与共享
  • 3.pthread_exit函数
  • 4.pthread_join函数
  • 5.各函数调用例子:
    • 5.1.pthread_self函数-pthread_create函数-创建多线程
    • 5.2.strerror函数-检验系统最多能创建多少个线程
    • 5.3.线程之间共享全局变量
    • 5.4.pthread_exit函数调用-结束线程
    • 5.5.pthread_join函数调用-获取线程退出的返回值
    • 5.6.获取多线程的返回值

1.pthread_self函数

函数作用:
  获取线程ID。其作用对应进程中 getpid() 函数。
头文件:
  #include <pthread.h>
函数原型:
  pthread_t pthread_self(void);
函数参数:
  无
返回值:
  成功:返回线程的ID号;
失败:无!
注意:
  ①g++/gcc编译的时候需要加上参数-lpthread,编译pthread动态库。
  ②不应使用全局变量 pthread_t tid,在子线程中通过pthread_create传出参数来获取线程ID,而应使用pthread_self。
  ③线程ID:pthread_t类型,可理解为:typedef unsigned long int pthread_t;本质:在Linux下为无符号整数(%lu),其他系统中可能是结构体实现
   ④线程ID是进程内部,识别标志。(两个进程间,线程ID允许相同)

2.pthread_create函数

函数作用:
  创建一个新线程。 其作用,对应进程中fork() 函数。
头文件:
  #include <pthread.h>
函数原型:
  int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
函数参数:
  thread:传出参数,保存系统为我们分配好的线程ID。
  attr:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
  start_routine:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束,即创建线程的回调函数。
  arg:线程主函数执行期间所使用的参数。
返回值:
  成功:0;
  失败:错误号,可通过strerror函数打印错误信息。

  在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的函数指针start_routine决定。
  start_routine函数接收一个参数,是通过pthread_create的arg参数传递给它的,该参数的类型为void *,这个指针按什么类型解释由调用者自己定义。
  start_routine的返回值类型也是void *,这个指针的含义同样由调用者自己定义。
  start_routine返回时,这个线程就退出了,其它线程可以调用pthread_join得到start_routine的返回值,类似于父进程调用wait(2)得到子进程的退出状态,稍后详细介绍pthread_join。

  pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元。
  我们知道进程id的类型是pid_t,每个进程的id在整个系统中是唯一的,调用getpid(2)可以获得当前进程的id,是一个正整数值。线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self(3)可以获得当前线程的id。
  由于pthread_create的错误码不保存在errno中,因此不能直接用perror(3)打印错误信息,可以先用strerror(3)把错误码转换成错误信息再打印。

2.1.线程与共享

先抛出结论:线程间共享全局变量!

3.pthread_exit函数

函数作用:
  将单个线程退出。
头文件:
  #include <pthread.h>
函数原型:
  void pthread_exit(void *retval);
函数参数:
  retval:表示线程退出状态,通常传NULL。
返回值:
  无。
注意:
  线程中,禁止使用exit函数,会导致进程内所有线程全部退出。
  在不添加sleep控制输出顺序的情况下。pthread_create在循环中,几乎瞬间创建5个线程,但只有第1个线程有机会输出(或者第2个也有,也可能没有,取决于内核调度)如果第3个线程执行了exit,将整个进程退出了,所以全部线程退出了。
  所以,多线程环境中,应尽量少用,或者不使用exit函数,取而代之使用pthread_exit函数,将单个线程退出。任何线程里exit导致进程退出,其他线程未工作结束,主控线程退出时不能return或exit。
  另注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

线程调用return、pthread_exit、exit总结:
   return:返回到调用者那里去。
   pthread_exit():将调用该函数的线程
   exit: 将进程退出。

4.pthread_join函数

函数作用:
  阻塞等待线程退出,获取线程退出状态。
头文件:
  #include <pthread.h>
函数原型:
  int pthread_join(pthread_t thread, void **retval);
函数参数:
  thread:线程ID (【注意】:不是指针);
  retval:存储线程结束状态。
返回值:
  成功:0;
  失败:错误号,可通过strerror函数打印错误信息。
注意:
  调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
  1、如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
  2、如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
  3、如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
  4、如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

5.各函数调用例子:

5.1.pthread_self函数-pthread_create函数-创建多线程

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//通过命令:ps -Lf PID #查看PID进程下的线程
void *tfn(void *arg)
{int i;i = (int)arg;sleep(i);	 //通过i来区别每个线程printf("我是第%d个线程, 线程ID = %lu\n", i+1, pthread_self());return NULL;
}
int main(int argc, char *argv[])
{int n = 5, i;pthread_t tid;//创建5个进程for (i = 0; i < n; i++) {pthread_create(&tid, NULL, tfn, (void *)i);//将i转换为指针,在tfn中再强转回整形。}sleep(n);//程序暂停5sprintf("主线程ID == %lu\n", pthread_self());return 0;
}

5.2.strerror函数-检验系统最多能创建多少个线程

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
//线程回调函数
void *tfn(void *arg)
{while (1)sleep(1);
}
int main(void)
{pthread_t tid;int ret, count = 1;//循环一直创建,直至程序错误退出,检验你的系统最多创建多少个线程for (;;) {ret = pthread_create(&tid, NULL, tfn, NULL);if (ret != 0) {printf("%s\n", strerror(ret));break;}printf("---------%d---------------\n", ++count);}return 0;
}

5.3.线程之间共享全局变量

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>int var = 100;
//线程回调函数
void *tfn(void *arg)
{var = 200;printf("线程回调函数...\n");return NULL;
}int main(void)
{printf("改变之前:var = %d\n", var);//var=100pthread_t tid;pthread_create(&tid, NULL, tfn, NULL);//创建线程sleep(1);printf("改变之后:var = %d\n", var);//var=200return 0;
}

5.4.pthread_exit函数调用-结束线程

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//线程回调函数
void *tfn(void *arg)
{int i;i = (int)arg; //强转。if (i == 2){pthread_exit(NULL);//结束线程}sleep(i);	 //通过i来区别每个线程printf("我是第%d个线程, 线程ID = %lu\n", i+1, pthread_self());return NULL;
}
int main(int argc, char *argv[])
{int n = 5, i;pthread_t tid;for (i = 0; i < n; i++) {pthread_create(&tid, NULL, tfn, (void *)i);//将i转换为指针,在tfn中再强转回整形。}sleep(n);printf("主控线程ID = %lu\n", pthread_self());return 0;
}

5.5.pthread_join函数调用-获取线程退出的返回值

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
//自定义返回值
typedef struct {int a;int b;
} exit_t;
//线程回调函数
void *tfn(void *arg)
{exit_t *ret;ret = malloc(sizeof(exit_t)); //分配内存//改变值ret->a = 100;ret->b = 300;pthread_exit((void *)ret);
}
int main(void)
{pthread_t tid;exit_t *retval = NULL;pthread_create(&tid, NULL, tfn, NULL);//调用pthread_join可以获取线程的退出状态pthread_join(tid, (void **)&retval); //等待线程退出printf("a = %d, b = %d \n", retval->a, retval->b);//打印线程退出的返回值free(retval);//释放内存retval = NULL;//置NULLreturn 0;
}

5.6.获取多线程的返回值

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int var = 100;
//线程回调函数
void *tfn(void *arg)
{int i;i = (int)arg;sleep(i);//线程暂定isif (i == 1) {var = 333;printf("第%d个线程:var = %d\n", i+1,var);return (void *)var;} else  if (i == 3) {var = 777;printf("第%d个线程:var = %d\n", i+1, var);pthread_exit((void *)var);} 
else  {printf("第%d个线程:var = %d\n", i+1, var);pthread_exit((void *)var);}return NULL;
}
int main(void)
{pthread_t tid[5];int i;int *ret[5];  //创建5个线程for (i = 0; i < 5; i++){pthread_create(&tid[i], NULL, tfn, (void *)i);}for (i = 0; i < 5; i++) {//通过pthread_join获取线程返回状态pthread_join(tid[i], (void **)&ret[i]);printf("第%d个线程返回:%d\n", i+1, (int)ret[i]);}printf("主线程ID = %lu\t var = %d\n", pthread_self(), var);sleep(i);return 0;
}

以上就是本次的分享了,希望对大家有所帮助,欢迎关注博主一起学习更多的新知识!


http://www.ppmy.cn/news/60021.html

相关文章

MySQL索引详解及如何使用

前言 MySQL 索引是 MySQL 数据库中的一项重要功能&#xff0c;它可以大大提高查询效率&#xff0c;加快数据检索速度。在本文中&#xff0c;我们将深入探讨 MySQL 索引的相关知识&#xff0c;包括索引的作用、常用索引类型、如何创建和使用索引等。我们将会从以下四个方面进行…

代码随想录算法训练营第四十八天| 198.打家劫舍、213.打家劫舍II、337.打家劫舍III

文章目录 198.打家劫舍213.打家劫舍II337.打家劫舍III 198.打家劫舍 题目链接&#xff1a;代码随想录 解题思路&#xff1a; 1.dp[i]&#xff1a;考虑下标i&#xff08;包括i&#xff09;以内的房屋&#xff0c;最多可以偷窃的金额为dp[i] 只是考虑&#xff0c;不一定偷 2.递推…

mobile代码打APK包

1、安装Android SDK Android SDK 下载地址&#xff1a; http://www.androiddevtools.cn/ 下载位置 下载后解压 打开解压文件&#xff0c;点击 SDK Manager.exe 进行安装 安装组件&#xff0c;这要选 Android 8.0.0 或者以上版本 再次安装&#xff0c;发现没什么可以安装了 2…

【在homeassistant的ONVIF中配置TP-Link】

【在homeassistant的ONVIF中配置TP-Link】 1. 配置2. 手动配置步骤3. 配置说明4. 集成的额外配置5. 支持的传感器6. SERVICE ONVIF.PTZ7. 支持的交换机欢迎大家阅读2345VOR的博客【在homeassistant的ONVIF中配置TP-Link】,本页是在homeassistant的ONVIF中配置TP-Link教程🥳�…

Java开发手册-3

Java开发手册-3 编程规约日期时间集合处理 编程规约 日期时间 【强制】日期格式化时&#xff0c;传入pattern中表示年份统一使用小写的y。 说明&#xff1a;日期格式化时&#xff0c;yyyy表示当天所在的年&#xff0c;而大写的YYYY代表是week in whichyear&#xff0c;意思是当…

webpack loader原理以及自定义loader

loader主要是帮助webpac将不同类型的文件转换为webpack可识别的模块。 分类&#xff1a;enforce属性 pre 前置loader&#xff0c;normal 普通loader&#xff0c;inline&#xff1a;内联loader&#xff0c;post&#xff1a;后置loader 如果不写默认是 normal类型 执行顺序&a…

pytorch——损失函数之nn.L1Loss()和nn.SmoothL1Loss()

文章目录 【回归损失函数】L1&#xff08;MAE&#xff09;、L2&#xff08;MSE&#xff09;、Smooth L1 Loss详解1. L1 Loss&#xff08;Mean Absolute Error&#xff0c;MAE&#xff09;1.1 数学定义1.2 、使用场景与问题1.3 、如何使用 2. L2 Loss&#xff08;Mean Squared E…

SPSS如何制作基本统计分析报表之案例实训?

文章目录 0.引言1.制作在线分析处理报告2.制作个案摘要报告3.制作行形式摘要报告4.制作列形式摘要报告 0.引言 因科研等多场景需要进行数据统计分析&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记…