【嵌入式Linux应用开发基础】多线程编程

news/2025/2/24 9:23:25

目录

一、基本概念

二、相关 API

2.1.  线程创建

2.2.  线程等待 

2.3.  线程退出 

2.4.  互斥锁

2.5.  条件变量 

2.6. 使用示例

三、线程的属性设置

四、多线程编程中的问题和同步

五、多线程编程的实践

六、参考资料


在嵌入式 Linux 应用开发中,多线程编程是一项非常重要的技术,它允许程序同时执行多个任务,提高系统的并发处理能力和响应速度。

一、基本概念

  • 线程:线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等,但每个线程有自己独立的栈空间和程序计数器。

  • 多线程编程:多线程编程是指在一个程序中同时创建和管理多个线程,每个线程可以独立执行不同的任务。通过多线程编程,可以实现并发执行,提高程序的性能和效率。

  • 线程与进程的区别:线程共享进程资源(内存、文件描述符),创建和切换开销更小,适合资源受限的嵌入式系统。

  • POSIX线程库(pthread):Linux下多线程开发的标准API,需链接-lpthread

二、相关 API

在 Linux 系统中,使用 POSIX 线程库(pthread)来进行多线程编程。以下是一些常用的 API:

2.1.  线程创建

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
  • 参数说明
    • thread:指向pthread_t类型的指针,用于存储新创建线程的 ID。
    • attr:指向pthread_attr_t类型的指针,用于设置线程的属性,若为NULL,则使用默认属性。
    • start_routine:线程的入口函数,该函数的返回值和参数类型都为void *
    • arg:传递给线程入口函数的参数。
  • 返回值:成功返回 0,失败返回错误码。

2.2.  线程等待 

#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);
  • 参数说明
    • thread:要等待的线程的 ID。
    • retval:指向void *类型的指针,用于存储线程的返回值。
  • 返回值:成功返回 0,失败返回错误码。

2.3.  线程退出 

#include <pthread.h>

void pthread_exit(void *retval);
  • 参数说明retval:线程的返回值。

2.4.  互斥锁

#include <pthread.h>

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • 功能说明
    • pthread_mutex_init:初始化互斥锁。
    • pthread_mutex_lock:加锁,若互斥锁已被其他线程持有,则当前线程会阻塞。
    • pthread_mutex_unlock:解锁。
    • pthread_mutex_destroy:销毁互斥锁。

2.5.  条件变量 

#include <pthread.h>

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_destroy(pthread_cond_t *cond);
  • 功能说明
    • pthread_cond_init:初始化条件变量。
    • pthread_cond_wait:等待条件变量,会自动释放互斥锁,被唤醒后会重新加锁。
    • pthread_cond_signal:唤醒一个等待该条件变量的线程。
    • pthread_cond_broadcast:唤醒所有等待该条件变量的线程。
    • pthread_cond_destroy:销毁条件变量。 

2.6. 使用示例

以下是一个简单的多线程编程示例,包含线程创建、线程等待和互斥锁的使用:

#include <stdio.h>
#include <pthread.h>

// 定义互斥锁
pthread_mutex_t mutex;
// 共享资源
int shared_variable = 0;

// 线程函数
void* thread_function(void* arg) {
    int i;
    for (i = 0; i < 100000; i++) {
        // 加锁
        pthread_mutex_lock(&mutex);
        shared_variable++;
        // 解锁
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;

    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 创建线程
    pthread_create(&thread1, NULL, thread_function, NULL);
    pthread_create(&thread2, NULL, thread_function, NULL);

    // 等待线程结束
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    // 输出共享资源的值
    printf("Shared variable value: %d\n", shared_variable);

    return 0;
}

编译和运行:使用以下命令编译上述代码

gcc -o multi_thread_example multi_thread_example.c -lpthread

运行编译后的可执行文件:

./multi_thread_example

三、线程的属性设置

线程的属性可以通过pthread_attr_t结构体进行设置。以下是一些常见的线程属性:

  • 线程分离状态:可以通过pthread_attr_setdetachstate函数设置线程为分离状态,这样线程在终止时会自动释放资源,而不需要其他线程调用pthread_join来等待。
  • 线程栈大小:可以通过pthread_attr_setstacksize函数设置线程的栈大小。
  • 线程调度策略:可以通过pthread_attr_setschedpolicy等函数设置线程的调度策略和优先级。
  • 设置线程属性:如分离状态、栈大小、调度策略。
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  • 优先级与调度策略:实时系统常用SCHED_FIFOSCHED_RR
struct sched_param param;
param.sched_priority = 10;
pthread_attr_setschedpolicy(&attr, SCHED_RR);
pthread_attr_setschedparam(&attr, &param);

四、多线程编程中的问题和同步

  • 竞态条件:当多个线程同时访问共享资源,并且至少有一个线程在修改该资源时,就可能发生竞态条件。竞态条件会导致程序的行为变得不确定。
  • 死锁:当两个或多个线程相互等待对方释放资源,从而无法继续执行时,就发生了死锁。死锁是一种严重的并发问题,通常会导致程序崩溃。

为了解决这些问题,需要使用同步机制来协调线程之间的执行。常见的同步机制包括:

  • 互斥锁:互斥锁用于保护临界资源,确保同一时间只有一个线程可以访问该资源。当线程需要访问临界资源时,会先尝试获取互斥锁;如果锁已被其他线程持有,则线程会阻塞等待直到锁被释放。
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock);
// 临界区操作
pthread_mutex_unlock(&lock);
  • 条件变量:条件变量用于线程间的同步,它允许线程在某些条件不满足时等待,并在条件满足时被唤醒。条件变量通常与互斥锁一起使用,以确保对共享资源的访问是安全的。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 等待条件
pthread_cond_wait(&cond, &mutex);
// 通知条件满足
pthread_cond_signal(&cond);
  • 信号量:信号量是一种更通用的同步机制,它可以用于控制对共享资源的访问数量。信号量的值表示可用资源的数量;当线程需要访问资源时,会先尝试对信号量进行P操作(减1);如果信号量的值大于0,则操作成功,线程可以继续执行;否则,线程会阻塞等待直到信号量的值大于0。当线程释放资源时,会对信号量进行V操作(加1),以唤醒等待的线程。

五、多线程编程的实践

在嵌入式Linux应用开发中,多线程编程的实践通常包括以下几个步骤:

  • 设计线程结构:根据应用程序的需求,设计合理的线程结构,包括线程的数量、职责和交互方式等。
  • 编写线程函数:为每个线程编写相应的执行函数,实现线程的具体功能。
  • 创建和管理线程:使用pthread库函数创建和管理线程,包括设置线程属性、启动线程和等待线程终止等。
  • 实现线程同步:使用互斥锁、条件变量和信号量等同步机制来协调线程之间的执行,确保程序的正确性和稳定性。
  • 测试和调试:对多线程程序进行充分的测试和调试,以发现和解决潜在的并发问题。

综上所述,多线程编程在嵌入式Linux应用开发中具有重要意义。通过合理设计和使用线程,可以充分利用CPU资源,提高程序的运行效率和响应速度。同时,也需要注意线程同步和互斥问题,以确保程序的正确性和稳定性。

六、参考资料

  • 《Unix 环境高级编程》:对 UNIX 环境下的进程、线程、文件操作、网络编程等进行了深入讲解,关于多线程编程部分详细介绍了线程的创建、同步、互斥等机制,是嵌入式 Linux 应用开发中多线程编程的经典参考书籍。
  • 《嵌入式 Linux 系统编程》:涉及嵌入式 Linux 系统设备驱动开发的各个环节,也包含 Linux 多线程相关内容,如线程的同步与互斥等知识,通过详细的示例,由浅入深地指导初学者掌握相关知识。
  • 《C Primer Plus》:虽然不是专门针对多线程编程,但十 C 语言的经典入门书籍。
  • POSIX 线程库文档:Linux 下多线程编程主要通过 POSIX 线程库来实现,官方的 POSIX 线程库文档是非常权威的参考资料,详细介绍了线程相关函数的使用方法、参数含义以及返回值等。
  • 开源项目代码:许多开源的嵌入式 Linux 项目中都有多线程编程的实际应用,如一些基于 Linux 的实时操作系统(RTOS)项目,通过阅读这些开源项目的代码,可以学习到实际应用中多线程编程的技巧和最佳实践。


http://www.niftyadmin.cn/n/5864171.html

相关文章

‌挖数据平台对接DeepSeek推出一键云端部署功能:API接口驱动金融、汽车等行业智能化升级

云端部署 引言&#xff1a;当数据生产力遇上云端智能化 2025年2月23日&#xff0c;国内领先的数据服务商挖数据平台宣布与人工智能巨头DeepSeek达成战略合作&#xff0c;正式推出“一键云端部署”功能。这一功能以API&#xff08;应用程序接口&#xff09;为核心&#xff0c;通…

c++入门-------命名空间、缺省参数、函数重载

C系列 文章目录 C系列前言一、命名空间二、缺省参数2.1、缺省参数概念2.2、 缺省参数分类2.2.1、全缺省参数2.2.2、半缺省参数 2.3、缺省参数的特点 三、函数重载3.1、函数重载概念3.2、构成函数重载的条件3.2.1、参数类型不同3.2.2、参数个数不同3.2.3、参数类型顺序不同 前言…

eNSP下载安装(eNsp、WinPcap、Wireshark、VirtualBox下载安装)

一、下载 下载网址&#xff1a;https://cloud.grbj.cn/softlink/eNSP%20V100R003C00SPC100%20Setup.exe 备用临时网址&#xff1a;https://linshi.grbj.cn/abdpana/softlink 二、准备工作 系统要求 关闭防火墙 三、安装 3.1安装WinPcap 基本都是下一步&#xff0c;双击&…

R与RStudio简介及安装

目录 一、R与RStudio关系 二、R简介 2.1. 发展历史 2.2. R语言特点 三、安装指南 3.1 R安装指南 3.2 R studio安装指南 一、R与RStudio关系 R是统计领域广泛使用的工具&#xff0c;属于GNU系统的一个自由、免费、源代码开放的软件&#xff0c;是 用于统计计算和统计绘图…

旋转位置编码(ROPE)详解:从Transformer到现代前沿

旋转位置编码&#xff08;ROPE&#xff09;详解&#xff1a;从Transformer到现代前沿 标签&#xff1a;NLP, Transformer, 位置编码, ROPE, 深度学习, 机器学习 摘要&#xff1a;本文详细介绍了旋转位置编码&#xff08;ROPE&#xff09;在Transformer模型中的应用&#xff0…

基于GWO灰狼优化的WSN网络最优节点部署算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 无线传感器网络&#xff08;Wireless Sensor Network, WSN&#xff09;由大量分布式传感器节点组成&#xff0c;用于监测物理或环境状况。节点部署是 WSN 的关键问…

Git Repo下如何制作一个patch文件

Git Repo下如何制作一个patch文件 1. 源由2. 步骤2.1 本地代码差异2.2 添加修改代码2.3 添加未跟踪代码2.4 确认打包文件2.5 输出打包文件2.6 自查打包文件2.7 恢复工作环境 3. 总结 1. 源由 patch分享&#xff0c;更好的差异化比较&#xff0c;减少时间浪费。同时&#xff0c…

【AI学习笔记】2月10日李飞飞巴黎AI峰会演讲:探索 AI 的历史、现状与未来

【AIGC学习笔记】2月10日李飞飞巴黎AI峰会演讲&#xff1a;探索 AI 的历史、现状与未来 AI 的历史根基与发展历程 生命起源与智能诞生&#xff1a;5 亿年前视觉概念的出现推动了智能的诞生。最初的感知仅仅是被动的体验&#xff0c;只是但随着神经系统的活跃&#xff0c;视觉…