Linux系统编程(五)多线程

目录

  • 一、基本知识点
  • 二、线程的编译
  • 三、 线程相关函数
    • 1. 线程的创建
    • 2. 线程的退出
    • 3. 线程的等待
    • 补充
  • 四、综合举例

  

一、基本知识点

   线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个标准的线程由线程ID、当前指令指针(PC)、寄存器集合和堆栈组成。它与同属一个进程的其他的线程共享进程的资源,如内存空间、文件描述符和其他一些进程相关的属性。
   相比于进程而言,线程更加轻量级,因为它们共享了进程的地址空间以及其他资源,所以线程之间的切换和通信会更加高效。一个进程可以包含多个线程,这些线程可以并发执行,各自独立完成一些特定的任务,或者共同完成一个复杂的任务。主线程结束,则所有线程结束。
在这里插入图片描述

   在多线程编程中,通常会涉及到线程的创建、同步、互斥、通信等操作,以确保线程之间的协调运行,避免资源竞争和数据不一致的问题。

二、线程的编译

   Linux 的线程是通过用户级的函数库实现的,一般采用 pthread 线程库实现线程的访问和控制。它用第 3 方 posix 标准的 pthread,具有良好的可移植性。在使用了线程的代码编译的时候要在后面加上 -lpthread

例如:gcc test.c -o test -lpthread

三、 线程相关函数

头文件:#include <pthread.h>

在这里插入图片描述

1. 线程的创建

int pthread_create(pthread_t* thread,  pthread_attr_t * attr, void *(*start_routine)(void *),  void * arg);
//pthread_t* thread :线程的句柄,用于区分是哪个线程。
//pthread_attr_t * attr :线程的属性,通常为NULL。
//void *(*start_routine)(void *) :线程所执行的函数,该函数形参和返回值都要为void *。
// void * arg :该值用于传递第三个参数函数的形参,如果不传递可以为NULL。

2. 线程的退出

   函数 pthread_exit 表示线程的退出。其传入的的参数可以被其它线程用 pthread_join 等待函数进行捕获。例如: pthread_exit( (void*)3 ); 表示线程退出,并将 3作为返回值被后面的 pthread_join 函数捕获。该函数的作用就是可以将该线程的计算结果传递给创建它的主线程或者其他线程。
   注意:在使用线程函数时,不能随意使用 exit 退出函数进行出错处理,由于 exit 的作用是使调用进程终止,往往一个进程包括了多个线程,所以在线程中通常使用 pthread_exit 函数来代替进程中的退出函数 exit。

void pthread_exit(void *retval);
//void *retval:作为线程退出时的值。如果不需要捕获该值,可以传入NULL。

3. 线程的等待

   当父线程结束的时候,如果没有 pthread_join 函数等待子线程执行的话,父线程会退出,而主线程的退出会导致进程的退出,故子线程也会退出。
   由于一个进程中的多个线程是共享数据段的,因此通常在线程退出之后,退出线程所占用的资源并不会随着线程的终止而得到释放。正如进程之间可以通过 wait()函数系统调用来同步终止并释放资源一样,线程之间也有类似的机制,那就是 pthread_join 函数。这个函数是一个线程阻塞函数,调用这函数的线程将一直等待直到被等待的线程结束为止,当函数返回时,被等待线程的资源被回收。

int pthread_join(pthread_t pthid, void **thread_return);
//pthread_t pthid :线程句柄。
//void **thread_return : 用于接收线程退出的返回值。如果没有需要接收的填NULL。

补充

一般线程的退出和线程的等待是一起使用的。这里我们使用几种参数类型进行举例。
(1)返回整型

int a=10;
pthread_exit((void *) &a);

(2)返回浮点数

int f=10.12;
pthread_exit((void *) &f);

(3)返回字符串

char *string="i love you!";
pthread_exit(string);

(4)返回结构体

typedef struct 
{char name[10];int  number;float score;
}student;
//方式一
student *people;
pthread_exit(people);
//方式二
student people;
pthread_exit((void *)&people);

举例:

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void *func1 (void *arg)
{int n=5;  float *p=(float *)arg; while(1){ if(n<=0) break; printf("我是子线程,参数为:%f\n", *p);n--;sleep(1);} pthread_exit( (void*)123 ); 	
}  int main(int argc, char **argv)
{int ret;int thread_result;     float f_number=0.255;  pthread_t thread1;  //线程句柄//创建线程:ret=pthread_create(&thread1, NULL, func1, (void *)&f_number); //最后一个参数要取地址!if(ret!=0){perror("pthread_create error!\n");return -1;}//等待子线程退出,并释放其占用的资源pthread_join(thread1, (void **)&thread_result);printf("thread_result:%d\n", thread_result);
}   

在这里插入图片描述

四、综合举例

#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void *fun1(void * arg)    //线程1函数
{float *num =(float *)arg;while(1){sleep(1);printf("这是子线程1,传入的值为%f\n",*num);}  
}void *fun2(void * arg)    //线程2函数
{int *num =(int *)arg;char *string="pthread2_end"while(1){  sleep(1);printf("这是子线程2,传入的值为%d\n",*num);*num--;if(*num <0) break;}pthread_exit((void *)&string);
}int main()
{float pthread1_arg=11.2;  //传入线程函数1的参数int pthread2_arg=3;  //传入线程函数2的参数int ret;pthread_t thread1,thread2;//线程句柄//创建线程1ret=pthread_create(&thread1, NULL, fun1, (void *) &pthread1_arg);if(ret<0) {perror("pthread1_create error!\n");return -1;}//创建线程2ret=pthread_create(&thread2, NULL, fun2, (void *) &pthread2_arg);if(ret<0) {perror("pthread2_create error!\n");return -1;}while(1){sleep(1);printf("我是主线程\n");}return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/19095.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【4.vi编辑器使用(下)】

一、vi编辑器的光标移动 二、vi编辑器查找命令 1、命令&#xff1a;:/string 查找字符串 n&#xff1a;继续查找 N&#xff1a;反向继续查找 /^the 查找以the开头的行 /end 查找以 查找以 查找以结尾的行 三、vi编辑器替换命令 1、语法: : s[范围,范围]str1/str2[g] g表示全…

可视化大屏:随意堆数据,错!要主次分明、重点突出,动静结合。

可视化大屏是一种展示数据的方式&#xff0c;它的设计应该遵循一些原则&#xff0c;以确保信息的传递和理解效果最佳。以下是一些关键点&#xff0c;可以帮助设计出主次分明、重点突出、动静结合的可视化大屏&#xff1a; 定义目标和重点&#xff1a; 在开始设计可视化大屏之前…

NumPy 泊松分布模拟与 Seaborn 可视化技巧

泊松分布 简介 泊松分布是一种离散概率分布&#xff0c;用于描述在给定时间间隔内随机事件发生的次数。它常用于模拟诸如客户到达商店、电话呼叫接入中心等事件。 参数 泊松分布用一个参数来定义&#xff1a; λ&#xff1a;事件发生的平均速率&#xff0c;表示在单位时间…

哈希表练习题(2024/5/29)

1有效的字母异位词 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 示例 1: 输入: s "anagram", t "nagaram" 输…

C语言数据结构堆排序、向上调整和向下调整的时间复杂度的计算、TopK问题等的介绍

文章目录 前言一、堆排序1. 排升序&#xff08;1&#xff09;. 建堆&#xff08;2&#xff09;. 排序 2. 拍降序&#xff08;1&#xff09;. 建堆&#xff08;2&#xff09;. 排序 二、建堆时间复杂度的计算1. 向上调整时间复杂度2. 向下调整时间复杂度 三、TopK问题总结 前言 …

Java事务入门:从基础概念到初步实践

Java事务入门&#xff1a;从基础概念到初步实践 引言1. Java事务基础概念1.1 什么是事务&#xff1f;1.2 为什么需要事务&#xff1f; 2. Java事务管理2.1 JDBC 的事务管理2.2 Spring 事务管理2.2.1 Spring JDBC2.2.1.1 添加 Spring 配置2.2.1.2 添加业务代码并测试验证 2.2.2…

Vue项目中使用router

Vite项目中使用router的步骤&#xff1a; 1.安装路由器库&#xff1a; npm install vue-router4 2.创建路由配置&#xff1a;通常命名为 router.js 或者 router/index.js import { createRouter, createWebHashHistory } from vue-router;import Login from ../views/Login.vu…

Jpg与png图片区别

Jpg与png图片有什么区别&#xff1f; JPG&#xff08;或JPEG&#xff09;和PNG是两种广泛使用的图像文件格式&#xff0c;它们在压缩技术、文件大小、图像质量、透明度支持等方面有显著的不同&#xff1a; 压缩技术: JPG: 使用有损压缩技术。这意味着在压缩过程中&#xff0c;一…

43-3 应急响应 - WebShell查杀工具

一、WebShell 简介 WebShell是一种以asp、php、jsp等网页文件形式存在的代码执行环境,通常用于网站管理、服务器管理和权限管理等操作。然而,如果被入侵者利用,它也可以用于控制网站服务器。具有完整功能的WebShell通常被称为"大马",而功能简单的则称为"小马…

20240529训练题目(西安交通大学 2024年程序设计竞赛校赛)

题目 D题 欢迎来到瑟莉姆大人的享乐宴会&#xff01; 宴会中一共有n个访客&#xff0c;编号1∼n。为了更好地控制影的力量&#xff0c;瑟莉姆要求有n−1个访客都恰好受 到另一个访客的支配&#xff0c;而剩下的那个人成为总支配者&#xff0c;支配其他n−1名访客。访客间的直…

监控易军队信息化运维:支持网闸隔离技术,实现多安全域的统一监控

随着信息技术的迅猛发展&#xff0c;军队的信息化建设也在不断推进&#xff0c;信息化运维成为了保障军队正常运作的关键环节。然而&#xff0c;军队的信息化运维现状仍面临诸多挑战&#xff0c;如设备种类多、数据处理量大、专业技术要求高以及信息安全隐患等。针对这些问题&a…

海外仓能用什么系统?一篇文章给你讲明白

海外仓作为跨境电商物流的重要组成部分&#xff0c;越来越受到国内企业的关注。对于中小型海外仓来说&#xff0c;怎么选择一个合适的海外仓系统&#xff0c;成为了一个亟待解决的问题。 今天我们就用一篇文章给大家讲清楚&#xff0c;怎么根据自己海外仓的特点&#xff0c;选…

MySQL sum后再计算percentage的多种解决办法

over() 函数&#xff0c;最简单的一种 以下是SQL片段&#xff0c;在外面嵌套一个Select是因为over 不会SQL语句所有的data sum&#xff0c;而不是 limit 之后的数据&#xff0c;所以需要先limit 在over&#xff08;&#xff09; SELECT b.*,ROUND(b.amount*100 / SUM(b.amount…

将IP添加到基础设计

将IP添加到基础设计 本节介绍将AXI IP添加到设计中。 添加低速外设&#xff08;AXI4 Lite&#xff09; 1.将等效IP添加到框图中。例如&#xff0c;对于AXI GPIO&#xff1a; a.右键单击方框图中的任意位置&#xff0c;然后选择“添加IP”。 b.搜索并双击AXI GPIO以添加IP。 2.双…

如何自己搭建一个简单的web api 环境 主流语言C# 编译器推荐VS2022

标题如何自己搭建一个简单的web api 环境 主流语言C# 编译器推荐VS2022 搭建一个简单的Web API环境&#xff0c;可以使用C#和Visual Studio 2022来实现。这里我们将使用ASP.NET Core来创建一个基本的Web API项目。以下是详细步骤&#xff1a; 安装必要的软件 Visual Studio 2…

[数据集]EEG数据集汇总

目录 1. EEG简介 2. 可用数据集 2.1. A large and rich EEG dataset for modeling human visual object recognition 2.2. A multi-modal open dataset for mental-disorder analysis 2.3. An EEG motor imagery dataset for brain computer interface in acute stroke pa…

双指针+前缀和,蓝桥云课 近似gcd

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 0近似gcd - 蓝桥云课 (lanqiao.cn) 二、解题报告 1、思路分析 考虑近似gcd的子数组的特点&#xff1a;不为g的倍数的数字个数小于等于1 我们用前缀和pre[]来存储不为g的倍数的数字个数 那么枚举左端点l&a…

数据结构(八)二叉树、哈希查找

文章目录 一、树&#xff08;一&#xff09;概念1. 前序遍历&#xff1a;根左右2. 中序遍历&#xff1a;左根右3. 后序遍历&#xff1a;左右根4. 层序遍历&#xff1a;需要借助队列实现 &#xff08;二&#xff09;代码实现&#xff1a;二叉树1. 结构体定义2. 创建二叉树1. 注意…

pytest识别测试用例的机制以及和unittest的区别

pytest识别测试用例的机制 文件 以test_开头或以_test结尾的python文件&#xff0c;即test_.py或_test.py类&#xff0c;在第一点识别到的文件中的类&#xff0c;且满足一下任一条件&#xff1a; 1&#xff09;以Test_开头&#xff0c;且没有__init__()初始化函数的类&#xf…

LED显示屏模组七大参数

LED模组是LED显示屏的核心组件&#xff0c;它包含LED线路板和外壳&#xff0c;将LED灯珠按照特定规则排列并封装&#xff0c;通常还会进行防水处理。随着LED显示屏行业的发展及其广泛应用&#xff0c;LED模组的功能和作用变得愈加重要。那么&#xff0c;LED模组的七大参数是什么…