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

linux——线程

在 Linux 系统中,进程和线程是两种重要的并发执行单元。本文将详细介绍它们的区别、使用场景、以及多线程编程中的关键API和示例代码。

进程与线程的区别

进程

  • 进程是程序运行的一个实例,承担分配系统资源的基本单位。
  • 每个进程都有独立的地址空间,一个进程崩溃不会影响其他进程。
  • 进程的创建和切换消耗较多资源。

线程

  • 线程是进程中的一个执行路径,是CPU调度的基本单位。
  • 线程共享进程的地址空间,但每个线程有自己的堆栈和局部变量。
  • 线程的创建和切换开销较小。
  • 如果一个线程崩溃,会导致整个进程崩溃。

使用线程的理由

  1. 节省资源:创建进程需要分配独立的地址空间,建立多个数据表来维护其代码段、数据段和堆栈段,这种方式十分昂贵。线程共享同一进程的地址空间和大部分数据,启动一个线程比启动一个进程要快很多。一个进程的开销大约是一个线程的30倍。
  2. 方便的通信机制:不同进程之间的数据传递需要通过通信机制,如管道、信号等,这种方式耗时且复杂。而线程共享进程的数据空间,数据共享非常方便和快捷,但需要注意数据同步的问题。

多线程开发及API

多线程开发主要包含三点:线程、互斥锁、条件变量。以下是具体的操作和API介绍:

线程操作

线程的创建
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
// 返回:若成功返回0,否则返回错误编号
线程的获取和比较
#include <pthread.h>
pthread_t pthread_self(void);
线程的等待
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 参数:
// pthread_t thread:等待的线程
// void **rval:线程退出状态的收回,NULL表示不收回
线程的退出
#include <pthread.h>
int pthread_exit(void *rval_ptr);

线程的创建、退出、等待示例

#include <stdio.h>
#include <pthread.h>void *func1(void *arg)
{static int ret = 10;printf("t1:%ld thread is created\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int *)arg));pthread_exit((void*)&ret); // 线程退出
}int main()
{int ret;int param = 100;int *pret = NULL;pthread_t t1;ret = pthread_create(&t1, NULL, func1, (void*)&param); // 创建线程if(ret == 0){printf("main: create t1 success\n");}printf("main: %ld\n", (unsigned long)pthread_self()); // 获取线程IDpthread_join(t1, (void**)&pret); // 等待线程退出printf("main: t1 quit with %d\n", *pret);return 0;
}

传入一个结构体的线程创建示例

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>struct data
{int a;char *s;
};void *func1(void *arg)
{static char *x = "t1 run out";struct data *temp;temp = (struct data*)arg;printf("t1:%ld pthread is created\n", (unsigned long)pthread_self());printf("t1: %d\n", temp->a);printf("t1: %s\n", temp->s);pthread_exit((void*)x);
}int main()
{int ret;pthread_t t1;char *pret = NULL;struct data *p = (struct data*)malloc(sizeof(struct data));p->a = 1;p->s = "xiancheng";ret = pthread_create(&t1, NULL, func1, (void*)p);if(ret == 0){printf("main: create t1 success\n");}printf("main: %ld\n", (unsigned long)pthread_self());pthread_join(t1, (void**)&pret);printf("main: t1 quit with %s\n", pret);free(p);return 0;
}

线程共享空间验证示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int g_data = 10;void *func1(void *arg)
{printf("t1:%ld thread is created\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int*)arg));while(1){printf("%d\n", g_data++);sleep(1);if(g_data == 3){pthread_exit(NULL);}}
}void *func2(void *arg)
{printf("t2:%ld thread is created\n", (unsigned long)pthread_self());printf("t2: parameter is %d\n", *((int*)arg));while(1){printf("%d\n", g_data++);sleep(1);}
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;ret = pthread_create(&t1, NULL, func1, (void*)&param);if(ret == 0){printf("main: create t1 success\n");}ret = pthread_create(&t2, NULL, func2, (void*)&param);if(ret == 0){printf("main: create t2 success\n");}printf("main: %ld\n", (unsigned long)pthread_self());while(1){printf("%d\n", g_data++);sleep(1);} pthread_join(t1, NULL);pthread_join(t2, NULL);return 0;
}

互斥锁(Mutex)

互斥锁API
创建及销毁互斥锁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *restrict mutex);
加锁及解锁
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *restrict mutex);
int pthread_mutex_trylock(pthread_mutex_t *restrict mutex);
int pthread_mutex_unlock(pthread_mutex_t *restrict mutex);

使用互斥锁的示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int g_data = 0;
pthread_mutex_t mutex; // 定义锁void *func1(void *arg)
{pthread_mutex_lock(&mutex); // 加锁for(int i = 0; i < 5; i++){printf("t1: %ld thread is created\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int*)arg));sleep(1);}pthread_mutex_unlock(&mutex); // 解锁
}void *func2(void *arg)
{pthread_mutex_lock(&mutex);for(int i = 0; i < 5; i++){printf("t2: %ld thread is created\n", (unsigned long)pthread_self());printf("t2: parameter is %d\n", *((int*)arg));sleep(1);}pthread_mutex_unlock(&mutex);
}void *func3(void *arg)
{pthread_mutex_lock(&mutex);for(int i = 0; i < 5; i++){printf("t3: %ld thread is created\n", (unsigned long)pthread_self());printf("t3: parameter is %d\n", *((int*)arg));sleep(1);}pthread_mutex_unlock(&mutex);
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_t t3;pthread_mutex_init(&mutex, NULL); // 初始化锁ret = pthread_create(&t1, NULL, func1, (void*)&param);if(ret == 0){printf("main: create t1 success\n");}ret = pthread_create(&t2, NULL, func2, (void*)&param);if(ret == 0){printf("main: create t2 success\n");}ret = pthread_create(&t3, NULL, func3, (void*)&param);if(ret == 0){printf("main: create t3 success\n");}printf("main: %ld\n", (unsigned long)pthread_self());pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_mutex_destroy(&mutex); // 收回锁return 0;
}

互斥锁限制共享资源的访问示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int g_data = 0;
pthread_mutex_t mutex;void *func1(void *arg)
{printf("t1: %ld pthread is created\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int*)arg));while(1){pthread_mutex_lock(&mutex);printf("%d\n", g_data++);sleep(1);if(g_data == 3){pthread_mutex_unlock(&mutex);pthread_exit(NULL);}}
}void *func2(void *arg)
{printf("t2: %ld pthread is created\n", (unsigned long)pthread_self());printf("t2: parameter is %d\n", *((int*)arg));while(1){printf("%d\n", g_data);pthread_mutex_lock(&mutex);g_data++;pthread_mutex_unlock(&mutex);sleep(1); }
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_mutex_init(&mutex, NULL);ret = pthread_create(&t1, NULL, func1, (void*)&param);if(ret == 0){printf("main: create t1 success\n");}ret = pthread_create(&t2, NULL, func2, (void*)&param);if(ret == 0){printf("main: create t2 success\n");}printf("main: %ld\n", (unsigned long)pthread_self());pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&mutex);return 0;
}

死锁示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>pthread_mutex_t mutex;
pthread_mutex_t mutex2;void *func1(void *arg)
{pthread_mutex_lock(&mutex);sleep(1);pthread_mutex_lock(&mutex2);for(int i = 0; i < 5; i++){printf("t1: %ld\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int *)arg));sleep(1);}pthread_mutex_unlock(&mutex);pthread_mutex_unlock(&mutex2);
}void *func2(void *arg)
{pthread_mutex_lock(&mutex2);sleep(1);pthread_mutex_lock(&mutex);for(int i = 0; i < 5; i++){printf("t2: %ld\n", (unsigned long)pthread_self());printf("t2: parameter is %d\n", *((int *)arg));sleep(1);}pthread_mutex_unlock(&mutex2);pthread_mutex_unlock(&mutex);
}void *func3(void *arg)
{pthread_mutex_lock(&mutex);for(int i = 0; i < 5; i++){printf("t3: %ld\n", (unsigned long)pthread_self());printf("t3: parameter is %d\n", *((int *)arg));sleep(1);}pthread_mutex_unlock(&mutex);
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_t t3;pthread_mutex_init(&mutex, NULL);pthread_mutex_init(&mutex2, NULL);ret = pthread_create(&t1, NULL, func1, (void*)&param);if(ret == 0){printf("main: create t1 success\n");}ret = pthread_create(&t2, NULL, func2, (void*)&param);if(ret == 0){printf("main: create t2 success\n");}ret = pthread_create(&t3, NULL, func3, (void*)&param);if(ret == 0){printf("main: create t3 success\n");}printf("main: %ld\n", (unsigned long)pthread_self());pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_mutex_destroy(&mutex);pthread_mutex_destroy(&mutex2);return 0;
}

条件变量实现线程同步

条件变量API
创建及销毁条件变量
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t cond);
等待
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout);
触发
#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *restrict cond);
int pthread_cond_broadcast(pthread_cond_t cond);

使用条件变量的示例

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>int g_data = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;void *func1(void *arg)
{static int cnt = 10;printf("t1: %ld pthread is created\n", (unsigned long)pthread_self());printf("t1: parameter is %d\n", *((int*)arg));while(1){pthread_cond_wait(&cond, &mutex); // 等待if(g_data == 3){printf("t1 run=========================\n");}printf("t1: %d\n", g_data);g_data = 0;sleep(1);if(cnt++ == 10){exit(1);}}
}void *func2(void *arg)
{printf("t2: %ld pthread is created\n", (unsigned long)pthread_self());printf("t2: parameter is %d\n", *((int*)arg));while(1){printf("t2: %d\n", g_data);pthread_mutex_lock(&mutex);printf("%d\n", g_data++);if(g_data == 3){pthread_cond_signal(&cond); // 触发}pthread_mutex_unlock(&mutex);sleep(1);}
}int main()
{int ret;int param = 100;pthread_t t1;pthread_t t2;pthread_cond_init(&cond, NULL);pthread_mutex_init(&mutex, NULL);ret = pthread_create(&t1, NULL, func1, (void *)&param);if(ret == 0){printf("main: create t1 success\n");}ret = pthread_create(&t2, NULL, func2, (void *)&param);if(ret == 0){printf("main: create t2 success\n");}pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);return 0;
}

通过上述示例和API的讲解,本文详细介绍了Linux下进程与线程的区别、多线程开发的基本操作以及常见问题和解决方案。希望能够帮助大家更好地理解和使用多线程编程。

相关文章:

linux——线程

在 Linux 系统中&#xff0c;进程和线程是两种重要的并发执行单元。本文将详细介绍它们的区别、使用场景、以及多线程编程中的关键API和示例代码。 进程与线程的区别 进程 进程是程序运行的一个实例&#xff0c;承担分配系统资源的基本单位。每个进程都有独立的地址空间&…...

install nebula with source

linux 环境&#xff1a;ubuntu 2004 默认gcc 7.5 nebula requerment&#xff1a; g 8.5 above 下载source git clone --branch release-3.8 https://github.com/vesoft-inc/nebula.git install gcc g 11 apt install gcc-11 g-11 此时 linux环境存在多个版本gcc&#xff1a…...

拆分盘投资策略解析:机制、案例与风险考量

一、引言 随着互联网技术的迅猛发展和金融市场的不断创新&#xff0c;拆分盘这一投资模式逐渐崭露头角&#xff0c;成为投资者关注的焦点。它基于特定的拆分策略&#xff0c;通过调整投资者持有的份额和单价&#xff0c;实现了看似稳健的资产增长。本文旨在深入探讨拆分盘的运…...

Redis主从复制、哨兵模式以及Cluster集群

一.主从复制 1.主从复制的概念 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(Master)&#xff0c;后者称为从节点(Slave)&#xff1b;数据的复制是单向的&#xff0c;只能由主节点到从节点。默认情况下&#xff0c;…...

【chatgpt】npy文件和npz文件区别

npy文件和npz文件都是用于存储NumPy数组的文件格式。它们的主要区别如下&#xff1a; npy文件&#xff1a;这种文件格式用于存储单个NumPy数组。它是一种简单的二进制文件格式&#xff0c;可以快速地读写NumPy数组。 npz文件&#xff1a;这种文件格式是一个压缩包&#xff0c;…...

为什么IP地址会被列入黑名单?

您是否曾经历过网站访客数量骤减或电子邮件投递失败的困扰&#xff1f;这背后或许隐藏着一个常被忽略的原因&#xff1a;您的IP地址可能已经被列入了黑名单内。尽管您并没有进行任何违法的网络操作&#xff0c;但这个问题依然可能出现。那么&#xff0c;究竟黑名单是什么&#…...

【OceanBase诊断调优】—— 如何查找表被哪些其它表引用外键

本文详述如何查找指定表是否被其他表引用做外键。 适用版本 OceanBase 数据库所有版本。 MySQL 租户 obclient> select * from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME表名;Oracle 租户 obclient> SELECT TABLE_NAME FROM dba_constraint…...

网络编程常见问题

1、TCP状态迁移图 2、TCP三次握手过程 2.1、握手流程 1、TCP服务器进程先创建传输控制块TCB&#xff0c;时刻准备接受客户进程的连接请求&#xff0c;此时服务器就进入了LISTEN&#xff08;监听&#xff09;状态&#xff1b; 2、TCP客户进程也是先创建传输控制块TCB&#xff…...

回调函数的使用详解

实际工作中&#xff0c;经常使用回调函数。用来实现触发等机制&#xff0c;也是基于一些已开发好的底层平台&#xff0c;开发上层应用的常用方法。下面对回调函数做一个详细的解释。 目录 1. 简单的回调函数实例 2. C11&#xff0c;使用function<>的写法 3. 注册函数 …...

<电力行业> - 《第8课:输电(一)》

1 输电环节的意义 电能的传输&#xff0c;是电力系统整体功能的重要组成环节。发电厂与电力负荷中心通常都位于不同地区。在水力、煤炭等一次能源资源条件适宜的地点建立发电厂&#xff0c;通过输电可以将电能输送到远离发电厂的负荷中心&#xff0c;使电能的开发和利用超越地…...

【python学习】 __pycache__ 文件是什么

__pycache__文件是Python中的一个特殊目录&#xff0c;主要用于存储已编译的字节码文件&#xff08;.pyc文件&#xff09;。以下是关于__pycache__文件的详细解释&#xff1a; 作用&#xff1a;当Python解释器执行一个模块时&#xff0c;它会首先检查是否存在对应的.pyc文件。…...

论文阅读_基本于文本嵌入的信息提取

英文名&#xff1a;Embedding-based Retrieval with LLM for Effective Agriculture Information Extracting from Unstructured Data 中文名&#xff1a;基于嵌入的检索&#xff0c;LLM 从非结构化数据中提取有效的农业信息 地址: https://arxiv.org/abs/2308.03107 时间&…...

kafka学习笔记08

Springboot项目整合spring-kafka依赖包配置 有这种方式&#xff0c;就是可以是把之前test里的配置在这写上&#xff0c;用Bean注解上。 现在来介绍第二种方式&#xff1a; 1.添加kafka依赖&#xff1a; 2.添加kafka配置方式: 编写代码发送消息&#xff1a; 测试&#xff1a; …...

Flask的 preprocess_request

理解 Flask 类似框架中的 preprocess_request 方法 在 Flask 类似的 web 框架中&#xff0c;preprocess_request 方法是一个关键组件。它在请求被分派之前调用&#xff0c;用于执行一些预处理操作。让我们一步一步来理解这个方法的工作原理。 1. 方法概述 首先&#xff0c;我…...

重温react-05(类组件生命周期和性能优化)

类组件的生命周期 import React, { Component } from reactexport default class learnReact05 extends Component {state {number: 1}render() {return (<div>{this.state.number}</div>)}// 一般将请求的方法,放在这个生命周期componentDidMount() {setInterva…...

RHCE四---web服务器的高级优化方案

一、Web服务器&#xff08;2&#xff09; 基于https协议的静态网站 概念解释 HTTPS&#xff08;全称&#xff1a;Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext TransferProtocol Secure&#xff0c;超文本传输安全协议&#xff09;&#xff0c;是以…...

Pytest集成Allure生成测试报告

# 运行并输出报告在Report文件夹下 查看生成的allure报告 1. 生成allure报告&#xff1a;pycharm terminal中输入命令&#xff1a;产生报告文件夹 pytest -s --alluredir../report 2. pycharm terminal中输入命令&#xff1a;查看生成的allure报告 allure serve ../report …...

SpringBoot 参数校验

参数校验 引入springvalidation依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId> </dependency>参数前添加Pattern public Result registry(Pattern(regexp &qu…...

【Arduino】实验使用ESP32控制可编程继电器制作跑马灯(图文)

今天小飞鱼实验使用ESP控制继电器&#xff0c;为了更好的掌握继电器的使用方法这里实验做了一个跑马灯的效果。 这里用到的可编程继电器&#xff0c;起始原理并不复杂&#xff0c;同样需要ESP32控制针脚输出高电平或低电平给到继电器&#xff0c;继电器使用这个信号控制一个电…...

islower()方法——判断字符串是否全由小写字母组成

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 islower()方法用于判断字符串是否由小写字母组成。islower()方法的语法格式如下&#xff1a; str.islower() 如果字符串中包含至少一个区…...

All in Token,三个运营商建Token工厂,中国移动跟进Token经营 三大运营商争夺AI阵地

随着Token&#xff08;词元&#xff09;经营战略的密集落地&#xff0c;三大运营商在AI领域的竞争愈发激烈。在日前举行的2026移动云大会上&#xff0c;中国移动正式发布了Token运营生态体系与移动模型服务平台MoMA&#xff0c;宣布接入超300款模型&#xff0c;并通过Token集约…...

从零构建本地化AI代码助手:架构、微调与工程实践

1. 项目概述&#xff1a;从零构建你自己的Claude代码助手最近在开发者社区里&#xff0c;一个名为“build-your-claude-code-from-scratch”的项目引起了我的注意。这个标题本身就充满了吸引力——它暗示着一种可能性&#xff1a;我们是否能够不依赖任何现成的、闭源的商业API&…...

模拟电路布局优化:多智能体强化学习实践

1. 模拟电路布局优化的挑战与机遇在集成电路设计领域&#xff0c;模拟电路布局一直是个令人头疼的问题。作为一名从业十余年的模拟电路设计师&#xff0c;我深刻体会到传统布局方法在面对现代工艺挑战时的局限性。每次手工调整晶体管位置时&#xff0c;那种"差之毫厘&…...

湿版摄影×AI生成革命:为什么93%的MJ用户调不出真实碘化银斑痕?——资深暗房师+AI训练师双视角深度拆解

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;湿版摄影AI生成革命&#xff1a;为什么93%的MJ用户调不出真实碘化银斑痕&#xff1f;——资深暗房师AI训练师双视角深度拆解 湿版火棉胶摄影术诞生于1851年&#xff0c;其不可复制的物理噪点——由碘化…...

【仿真学习框架】HoloMotion 从入门到精通:全身人形控制 Foundation Model 完全指南

HoloMotion 从入门到精通:全身人形控制 Foundation Model 完全指南 目标读者:具身智能研究者、人形机器人开发者、RL/机器人学习工程师 目录 第1章 HoloMotion 全景概览 1.1 什么是 HoloMotion 1.2 技术定位:"小脑"基座模型 1.3 4-Any 愿景与路线图 1.4 核心能力矩…...

TransPrompt:结构化提示词工程,提升LLM应用开发效率

1. 项目概述&#xff1a;当提示词工程遇上结构化工具最近在折腾大语言模型应用开发的朋友&#xff0c;估计都绕不开一个核心痛点&#xff1a;如何高效、稳定地管理那些越来越复杂、越来越长的提示词&#xff08;Prompt&#xff09;。直接写在代码里&#xff1f;改起来麻烦&…...

手把手教你用SystemVerilog Interface搭建一个可复用的DMA寄存器验证环境

基于SystemVerilog Interface构建模块化DMA验证环境的工程实践 在数字IC验证领域&#xff0c;DMA&#xff08;直接内存访问&#xff09;控制器作为关键IP核&#xff0c;其寄存器验证环境的搭建效率直接影响项目进度。传统验证方法中信号连接冗长、时序控制分散的问题&#xff…...

微服务架构实战:从DDD设计到K8s部署的完整指南

1. 项目概述与核心价值最近几年&#xff0c;微服务架构的热度一直居高不下&#xff0c;从互联网大厂到初创团队&#xff0c;几乎人人都在谈微服务。但说实话&#xff0c;真正能把微服务玩转、落地&#xff0c;并且能稳定支撑业务发展的团队&#xff0c;其实并不多。很多项目要么…...

React Native聊天UI组件库集成指南:从Sendbird UIKit入门到高级定制

1. 项目概述&#xff1a;一个开箱即用的React Native聊天UI组件库如果你正在用React Native开发一个需要集成聊天功能的App&#xff0c;并且希望这个聊天界面看起来专业、交互流畅&#xff0c;同时你又不想从零开始造轮子&#xff0c;那么你很可能已经听说过或者正在寻找一个合…...

云端生信分析:从零部署RStudio Server避坑指南

1. 为什么需要云端RStudio Server&#xff1f; 做生物信息分析的朋友们肯定深有体会&#xff0c;单细胞测序、转录组这些数据动辄几十GB&#xff0c;用自己电脑跑分析简直是折磨。我去年处理一个肝癌单细胞项目时&#xff0c;光是读取数据就卡了半小时&#xff0c;更别说后续的…...