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

IO进程线程(八)线程

文章目录

  • 一、线程(LWP)概念
  • 二、线程相关函数
    • (一)创建 pthread_create
      • 1. 定义
      • 2. 使用(不传参)
      • 3. 使用(单个参数)
      • 4. 使用(多个参数)
      • 5. 多线程执行的顺序
      • 6. 多线程内存空间
    • (二)获取线程号 pthread_self
    • (三)退出线程 pthread_exit
    • (四)线程 pthread_join
    • (五)标记分离态 pthread_detach
    • (六)取消线程pthread_cancel
    • (七)多线程文件拷贝
  • 三、线程的互斥
    • (一)定义和初始化
    • (二)上锁
    • (三)解锁
    • (四)销毁

一、线程(LWP)概念

轻量级的进程,进程是资源分配的基本单位,线程是系统调度的基本单位。

线程不会分配内存空间,一个进程中的多个线程是共用进程的内存空间的(0-3G)
多线程没有多进程安全,但是多线程的效率更高。

每个线程都有自己的task_struct结构体,每个线程都独立的参与时间片轮转

多线程的函数是第三方库实现的。
编码时需要加头文件 #include <pthread.h>
编译时 需要链接 线程库 -lpthread

线程之间是相互平等的

二、线程相关函数

(一)创建 pthread_create

1. 定义

#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);功能:创建线程参数:thread:线程id  tid  attr:线程属性 NULL 表示默认属性start_routine:线程体(线程处理函数)arg:给线程处理函数传参的 如果没有参数可传 可以置NULL返回值:成功  0失败  错误码
  • 注:
  • pthread_t是一个long类型的数
  • start_routine是返回值和参数都是void*的函数指针
  • 主线程结束,整个进程结束

2. 使用(不传参)

#include <my_head.h>//线程处理函数
void *task_func(void *arg){printf("我是子线程\n");
}int main(int argc, const char *argv[])
{pthread_t tid = 0;int ret = 0;if(0 != (ret = pthread_create(&tid, NULL, task_func, NULL))){printf("pthread_create : %s\n", strerror(ret));exit(-1);}printf("我是主线程\n");return 0;
}
  • 注:在不传参时,最后一个参数可以置NULL

3. 使用(单个参数)

4. 使用(多个参数)

5. 多线程执行的顺序

多线程执行也没有先后顺序,也是时间片轮转,上下文切换

6. 多线程内存空间

同一个进程中的多个线程共用进程内存空间
全局区、堆区、字符串常量区都是公用的
只有栈区是每个线程独立的(作用域问题)
线程之间通信简单,使用全局变量即可,但是不安全

(二)获取线程号 pthread_self

#include <pthread.h>pthread_t pthread_self(void);功能:获取调用线程的线程号 tid参数:无返回值:总是会成功 返回tid

ps -eLf 此时显示的线程号经过了优化方便人查看,并非实际的线程号

(三)退出线程 pthread_exit

#include <pthread.h>
void pthread_exit(void *retval);
功能:退出当前的线程
参数:retval:退出线程时返回的状态值(其他线程用pthread_join来接收)
返回值:无

线程退出的四种情况:

  1. 线程处理函数执行结束
  2. 线程中调用pthread_exit退出
  3. 同一进程中的任一线程中调用exit或者主函数return
  4. 接收到发送的pthread_cancel取消信号时

(四)线程 pthread_join

结合态线程:结束时必须由其他线程(并没有要求必须创建这个线程的线程来调用)调用pthread_join来回收资源,如果结合态的线程结束后没有回收资源,默认属性是结合态。
分离态线程:结束时由操作系统自动回收其资源

#include <pthread.h>int pthread_join(pthread_t thread, void **retval);功能:等待指定的结合态的线程结束 为其回收资源参数:thread:等待结束的线程号retval:线程结束时的退出状态值 如果不关心可以传NULL返回值:成功  0失败  错误码
  • 注:
  • 该函数是阻塞等待
  • 第二个参数一般传NULL,不关心返回值
  • 注意不能返回局部变量的地址,可以返回全局变量的地址,或者static修饰的局部变量的地址,或者malloc在堆区分配的地址(但是要注意回收资源的线程要free)

(五)标记分离态 pthread_detach

#include <pthread.h>int pthread_detach(pthread_t thread);功能:标记一个线程为分离态 结束时由操作系统自动回收资源参数:thread:线程号返回值:成功 0失败 错误码
  • 注:在主线程和子线程本身中标记子线程为分离态均可以,但是在子线程中标记自己更好,因为线程执行不分先后顺序,在子线程中标记,可以确保在子线程未执行结束前可以标记成功。
  • 一般在子线程开头进行标记,当作是线程属性的一种

(六)取消线程pthread_cancel

#include <pthread.h>
int pthread_cancel(pthread_t thread);
功能:给线程发一个取消的请求目标线程是否以及何时响应这个请求取决于线程的两种属性:statu和type
参数:thread:线程id
返回值:成功 0失败 错误码
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
//设置线程是否可被取消
PTHREAD_CANCEL_ENABLE  可被取消  ----默认属性
PTHREAD_CANCEL_DISABLE  不可被取消
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
//设置线程的取消类型
PTHREAD_CANCEL_DEFERRED   延时取消   ----默认属性直到线程下一次调用能作为取消点的函数时才会被取消
PTHREAD_CANCEL_ASYNCHRONOUS   立即取消

不可被取消,不接收取消信号
可被取消,立即取消,在接收到取消信号后立即取消;
可被取消,延时取消,在接收到取消信号先将当前命令执行完后,如果再次遇到可作为取消点的函数时被取消;如果遇不到就无法取消

  • 注:默认是可被取消,延时取消

(七)多线程文件拷贝

功能需求
使用多线程拷贝文件

代码实现

//实现多线程拷贝文件
#include <my_head.h>typedef struct _msg{char *src_file;char *dest_file;int offset;int len;
}msg_t;//初始化:保证有一个清空的目标文件,获取源文件的长度
int init_cp(const char *src_file, const char *dest_file){//打开一个目标文件,不存在就创建,存在就清空FILE *dest_fp=fopen(dest_file,"w");if(NULL == dest_fp) ERR_LOG("open dest file error");fclose(dest_fp);//获取源文件长度FILE *src_fp=fopen(src_file,"r");if(NULL == src_fp) ERR_LOG("open src file error");fseek(src_fp,0,SEEK_END);int size = ftell(src_fp);fclose(src_fp);return size;
}//线程处理函数
void *func_cp(void *argv1){printf("子线程函数:%ld\n",pthread_self());//使用结构体接收参数msg_t t_argv=*(msg_t *)argv1;//打开文件int src_fd = open(t_argv.src_file,O_RDONLY);if(-1 == src_fd) ERR_LOG("open src file error");int dest_fd = open(t_argv.dest_file,O_WRONLY);if(-1 == dest_fd) ERR_LOG("open dest file error");//将两个文件的指针移动到offset位置lseek(src_fd,t_argv.offset,SEEK_SET);lseek(dest_fd,t_argv.offset,SEEK_SET);//复制函数int w_byte=0;//记录写入的字节数int r_byte=0;//记录本次读到的字节数char buff[10];//缓冲区while(0 < (r_byte=read(src_fd,buff,sizeof(buff)))){w_byte+=r_byte;if(w_byte>=t_argv.len){write(dest_fd,buff,t_argv.len-(w_byte-r_byte));break;}write(dest_fd,buff,r_byte);}//自己就结束了
}int main(int argc, char const *argv[])
{if(3 != argc){printf("Usage:%s src dest\n",argv[0]);exit(-1);}//初始化int size = init_cp(argv[1],argv[2]);char src_path[20]={0};char dest_path[20]={0};strcpy(src_path,argv[1]);strcpy(dest_path,argv[2]);//创建线程msg_t argv2={src_path,dest_path,0,size/2};pthread_t tid1=0;int sta=0;if(sta = pthread_create(&tid1,NULL,func_cp,(void *)&argv2)){printf("pthread_create error:%s\n",strerror(sta));}msg_t argv1={src_path,dest_path,size/2,size-size/2};pthread_t tid2=0;if(sta = pthread_create(&tid2,NULL,func_cp,(void *)&argv1)){printf("pthread_create error:%s\n",strerror(sta));}pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}

进阶版:线程数由命令行传参进来

三、线程的互斥

保证临界资源同一时刻仅被一个线程访问

  • 注:
  • 上锁范围尽量小,尽量在进程访问临界变量时再上锁
  • 只有加锁的线程可以解锁
  • 对临界变量加锁,利用的是锁自身机制:一个线程加锁,另一个线程想要加锁会阻塞
  • 不要出现死锁:退出线程前,解锁;一次只拿一把锁。

(一)定义和初始化

#include <pthread.h>
//静态初始化
pthread_mutex_t lock;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;//静态初始化
//动态初始化互斥锁
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);功能:动态初始化互斥锁参数:mutex:要初始化的锁mutexattr:属性 一般传 NULL 默认属性返回值:总是会成功 返回0

(二)上锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:上锁(如果没有锁可以上锁,线程将被阻塞)
参数:mutex 互斥锁指针
返回值:成功 0 失败 错误码int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:尝试上锁(如果没有锁可以上锁,线程不会被阻塞,而是立即返回错误)
参数:mutex 互斥锁指针
返回值:成功 0 失败 错误码

(三)解锁

int pthread_mutex_unlock(pthread_mutex_t *mutex);功能:解锁(一般使用时,只有加锁的线程可以解锁)参数:mutex 互斥锁指针返回值:成功 0 失败 错误码

(四)销毁

int pthread_mutex_destroy(pthread_mutex_t *mutex);功能:在不需要使用互斥锁的时候销毁互斥锁参数:mutex 互斥锁指针返回值:成功 0 失败 错误码

相关文章:

IO进程线程(八)线程

文章目录 一、线程(LWP)概念二、线程相关函数&#xff08;一&#xff09;创建 pthread_create1. 定义2. 使用&#xff08;不传参&#xff09;3. 使用&#xff08;单个参数&#xff09;4. 使用&#xff08;多个参数&#xff09;5. 多线程执行的顺序6. 多线程内存空间 &#xff0…...

Linux基础指令网络管理003

本章主要讲述如何进行网络诊断。 操作系统&#xff1a; CentOS Stream 9 操作步骤&#xff1a; 操作指令 ping&#xff1a; 测试网络连接的连通性和延迟。 [rootlocalhost ~]# ping 192.168.80.111 PING 192.168.80.111 (192.168.80.111) 56(84) 比特的数据。 64 比特&a…...

在Android中使用 MQTT 服务实现消息通信

1.摘要 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输&#xff09;是一种轻量级的、基于发布/订阅&#xff08;Publish/Subscribe&#xff09;模式的通信协议&#xff0c;最初由 IBM 在1999年开发。它设计用于在低带宽、不稳定的网络环境下…...

qsort函数

学习c语言的过程中少不了的就是排序&#xff0c;例如冒泡排序&#xff08;不清楚的同学可以翻找一下之前的文章&#xff09;&#xff0c; 我们这里将冒泡排序作为一个自定义函数来呈现一下 #include<stdio.h>void bubble_sort(int arr[], int len) {for (int i 0; i &…...

你可以直接和数据库对话了!DB-GPT 用LLM定义数据库下一代交互方式,数据库领域的GPT、开启数据3.0 时代

✨点击这里✨&#xff1a;&#x1f680;原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 你可以直接和数据库对话了&#xff01;DB-GPT 用LLM定义数据库下一代交互方式&#xff0c;数据库领…...

数据结构笔记2 栈和队列

为什么在循环队列中&#xff0c;判断队满的条件是&#xff08;Q.rear1&#xff09;模maxqsize? 取模运算&#xff08;%&#xff09;在循环队列中起到关键作用&#xff0c;主要是因为它能确保索引值在数组的有效范围内循环。具体来说&#xff0c;取模运算有以下几个重要作用&am…...

Python | 刷题笔记

继承 class Father:__secret"you are your own kid"stroy"iam a handsome boy..."def tellstory(self):print("我的故事:",self.stroy)def __tellstory(self):print("我的秘密:",Father.__secret) class Son(Father):def tell(self…...

软件三班20240605

文章目录 1.创建工程和模块2.添加 web支持3.创建前端代码4.添加servlet 依赖5. 代码6.案例2 1.创建工程和模块 2.添加 web支持 方法1 方法2 3.创建前端代码 4.添加servlet 依赖 5. 代码 <!DOCTYPE html> <html lang"en"> <head><meta c…...

http和https数据传输与协议区分

目录 1. 数据传输安全性2. 端口号3. URL 前缀4. SSL/TLS 证书5. 性能6. SEO 和用户信任7. 应用场景总结 HTTP&#xff08;HyperText Transfer Protocol&#xff09;和 HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是用于在客户端&#xff08;如浏览器&…...

天才程序员周弈帆 | Stable Diffusion 解读(一):回顾早期工作

本文来源公众号“天才程序员周弈帆”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Stable Diffusion 解读&#xff08;一&#xff09;&#xff1a;回顾早期工作 在2022年的这波AI绘画浪潮中&#xff0c;Stable Diffusion无疑是最…...

软件架构初探

MVC架构软件层次结构是面向实体的&#xff0c;他最底层是实体类&#xff0c;实体类中封装了对象的抽象数据类型&#xff08;数据结构和对数据结构的基本操作&#xff09;。然后向上一层数据处理层提供接口&#xff0c;数据处理层利用模型层提供的对象和基本操作进一步进行算法的…...

Python01 -分解整包数据到各个变量操作和生成器

Python 的星号表达式可以用来解决这个问题。比如&#xff0c;你在学习一门课程&#xff0c;在学期末的时候&#xff0c;你想统计下家庭作业的平均成绩&#xff0c;但是排除掉第一个和最后一个分数。如果只有四个分数&#xff0c;你可能就直接去简单的手动赋值&#xff0c;但如果…...

flutter image_picker 执行拍照的图片怎么保存到本地

在 Flutter 中&#xff0c;使用 image_picker 插件拍照的图片默认会被保存到设备的临时目录中。这个临时目录的具体位置取决于设备的操作系统。在 iOS 上&#xff0c;它通常是应用的沙盒目录&#xff1b;在 Android 上&#xff0c;它通常是应用的缓存目录。 这些图片不会被自动…...

基于Python的北京天气数据可视化分析

项目用到库 import numpy as np import pandas as pd import datetime from pyecharts.charts import Line from pyecharts.charts import Boxplot from pyecharts.charts import Pie,Grid from pyecharts import options as opts from pyecharts.charts import Calendar 1.2…...

Linux编译器-gcc或g++的使用

一.安装gcc/g 在linux中是不会自带gcc/g的&#xff0c;我们需要编译程序就自己需要安装gcc/g。 很简单我们使用简单的命令安装gcc&#xff1a;sudo yum install -y gcc。 g安装&#xff1a;sudo yum install -y gcc-c。 我们知道Windows上区分文件&#xff0c;都是使用文件…...

一条sql的执行流程

文章地址 https://blog.csdn.net/qq_43618881/article/details/118657040 连接器 请求先走到连接器&#xff0c;与客户端建立连接、获取权限、维持和管理连接 mysql缓存池 如果要查找的数据直接在mysql缓存池里面就直接返回数据 分析器 请求已经建立了连接&#xff0c;现在…...

Android音乐播放器的思路处理

** 1.android音乐播放播放列表中下一首上一首随机播放的思路 ** 实现 Android 音乐播放器的播放列表中的下一首、上一首和随机播放功能涉及到对音乐列表的管理以及对播放顺序的控制。以下是实现这些功能的思路&#xff1a; 下一首和上一首功能&#xff1a; 维护一个音乐列表…...

算法课程笔记——可撤销并查集

算法课程笔记——可撤销并查集 Gv...

【排序算法】快速排序

一、定义&#xff1a; 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff08;也叫Hoare排序&#xff09;&#xff0c;是一种基于分治的排序方。其基本原理是将待排序的数组通过一趟排序分成两个独立的部分&#xff0c;其中一部分的所有数据比另一部分的所有数…...

OS复习笔记ch7-2

页式管理 学过计组的同学都了解一点页式管理&#xff0c;就是将内存划分成较小的、大小固定的、等大的块。现在OS引入了进程的概念&#xff0c;那么为了匹配内存的分块&#xff0c;同样把进程也划分成同样大小的块。 这里区分两个概念 The chunks of a process are called p…...

Docker镜像的制作

什么是Docker镜像&#xff1f; Docker镜像是一个轻量级、独立的可执行软件包&#xff0c;包含运行应用程序所需的一切&#xff1a;代码、运行时、系统工具、系统库和设置。镜像是容器的基础&#xff0c;容器是镜像的运行实例。 准备工作 安装Docker 首先确保你的系统已安装D…...

League-Toolkit英雄联盟工具集启动故障解决方案

League-Toolkit英雄联盟工具集启动故障解决方案 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Toolkit作为一款基于LCU A…...

Ollama + DeepSeek + 芋道框架 + SearXNG 本地联网搜索完整教程

1. 环境准备与检查 在开始之前,请确保你的环境满足以下条件: 1.1 硬件要求 内存:建议至少8GB可用内存(运行7B模型需要约4-6GB) 硬盘:DeepSeek模型文件约4-5GB空间 CPU/GPU:如有NVIDIA GPU可加速推理(可选) 1.2 软件要求 操作系统:Windows 10/11、macOS、Linux均可 …...

BLE5.1 与蓝牙Mesh 在手环数字车钥匙中的角色与体验升级

可穿戴数字车钥匙把传统实体钥匙的能力收敛到手环、手表等贴身设备上&#xff0c;通过近距无线链路与车载控制器或专用通信单元交互&#xff0c;支持解闭锁、启动、迎宾等操作。典型实现会组合 低功耗蓝牙&#xff08;BLE&#xff09; 做常在线链路与距离感知&#xff0c;并以 …...

OBS高级计时器:提升直播专业度的时间管理工具

OBS高级计时器&#xff1a;提升直播专业度的时间管理工具 【免费下载链接】obs-advanced-timer 项目地址: https://gitcode.com/gh_mirrors/ob/obs-advanced-timer 在直播行业竞争日益激烈的今天&#xff0c;精准的时间控制是提升直播质量的关键因素之一。OBS高级计时器…...

别再只盯着Midjourney了!2025年,这5款文生图模型更适合你的具体业务场景

2025年五大文生图模型实战指南&#xff1a;如何为你的业务精准匹配AI工具 当Midjourney成为文生图领域的"网红"时&#xff0c;真正懂行的从业者已经在根据具体业务需求选择更合适的工具了。就像专业摄影师不会只用一款镜头拍所有题材&#xff0c;明智的AI应用者需要建…...

别再只调参了!深入RepVgg设计思想,用CCFF模块优化你的模型特征融合效率

深入解析CCFF模块&#xff1a;用RepVgg思想重构跨尺度特征融合技术 在计算机视觉领域&#xff0c;特征融合一直是提升模型性能的关键环节。传统方法如FPN、PANet虽然有效&#xff0c;但在实时性要求高的场景下往往成为计算瓶颈。今天我们要探讨的CCFF&#xff08;Cross-scale C…...

FGF-21蛋白的代谢调控机制与临床转化前景

一、引言成纤维细胞生长因子21&#xff08;FGF-21&#xff09;是成纤维细胞生长因子家族中的一种内分泌代谢调节因子。自其被发现以来&#xff0c;该蛋白因其在糖脂代谢、能量稳态调控及胰岛素敏感性改善等方面的独特作用&#xff0c;逐渐成为代谢性疾病研究领域的前沿热点。与…...

如何在10分钟内实现AI助手与Figma的无缝协作?TalkToFigma Desktop完整指南

如何在10分钟内实现AI助手与Figma的无缝协作&#xff1f;TalkToFigma Desktop完整指南 【免费下载链接】cursor-talk-to-figma-mcp Cursor Talk To Figma MCP 项目地址: https://gitcode.com/GitHub_Trending/cu/cursor-talk-to-figma-mcp 您是否厌倦了在AI编程工具和Fi…...

基于人工电场搜索智能优化算法的水库发电和供水优化调度

基于人工电场搜索智能优化算法的水库发电和供水优化调度&#xff1b; 代码为MATLAB编写&#xff0c;可直接运行&#xff1b; 含有实例数据&#xff0c;点击即可运行&#xff0c;替换成自己数据点击即可出结果&#xff0c;如图。在水库管理中&#xff0c;实现发电和供水的优化调…...