Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例

2024-01-10 16:04

本文主要是介绍Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Linux和windows进程同步与线程同步那些事儿(一)
Linux和windows进程同步与线程同步那些事儿(二): windows线程同步详解示例
Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例
Linux和windows进程同步与线程同步那些事儿(四):windows 下进程同步
Linux和windows进程同步与线程同步那些事儿(五):Linux下进程同步

在Linux中,线程同步可以通过多种机制来实现,其中最常见的包括互斥锁(mutex)、条件变量(condition variable)和信号量(semaphore)。

1. 互斥锁(Mutex):

互斥锁是最常用的线程同步机制,它可以确保在同一时间只有一个线程可以访问共享资源。
在Linux中,可以使用pthread_mutex_t类型的互斥锁来实现线程同步。

代码示例:

#include <stdio.h>
#include <pthread.h>int global_variable = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* thread_function(void* arg) {for (int i = 0; i < 1000; i++) {// 加锁pthread_mutex_lock(&mutex);// 修改全局变量global_variable++;// 解锁pthread_mutex_unlock(&mutex);}return NULL;
}int main() {pthread_t thread1, thread2;// 初始化mutexpthread_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);// 销毁mutexpthread_mutex_destroy(&mutex);printf("Global variable value: %d\n", global_variable);return 0;
}

2. 条件变量(Condition Variable):

条件变量用于线程间的通信和同步,允许线程等待某个特定条件的发生。
在Linux中,可以使用pthread_cond_t类型的条件变量来实现线程同步。

条件变量是一种同步机制,它允许线程在满足特定条件之前等待,并在条件满足时被其他线程通知。

示例代码:演示如何使用条件变量来控制多线程修改全局变量的值:

#include <stdio.h>
#include <pthread.h>int global_var = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void* thread_function(void* arg)
{int new_value = *(int*)arg;pthread_mutex_lock(&mutex);// 等待条件满足while (global_var != 0){pthread_cond_wait(&cond, &mutex);}// 修改全局变量的值global_var = new_value;printf("Thread %d has modified global_var to %d\n", pthread_self(), global_var);// 通知其他线程条件已经满足pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mutex);return NULL;
}int main()
{pthread_t thread1, thread2;int value1 = 123, value2 = 456;// 创建两个线程pthread_create(&thread1, NULL, thread_function, &value1);pthread_create(&thread2, NULL, thread_function, &value2);pthread_join(thread1, NULL);pthread_join(thread2, NULL);printf("Final value of global_var is %d\n", global_var);return 0;
}

在上面的代码中,有两个线程分别调用thread_function函数。此函数接收一个整数参数作为新的全局变量值。线程首先获得互斥锁并进入临界区,然后使用pthread_cond_wait函数等待条件满足。只有当全局变量global_var的值为0时,线程才被允许修改这个变量的值。一旦满足这个条件,线程就会修改全局变量的值,并通过pthread_cond_broadcast函数通知其他等待这个条件的线程。最后,线程释放互斥锁并退出。

main函数中,我们创建了两个线程并等待它们完成。然后,我们打印最终的全局变量值。

通过使用条件变量,我们可以确保全局变量只能在满足特定条件时被修改,从而避免竞态条件和数据竞争的问题。

请注意,上述代码只是一个示例,用于说明如何使用条件变量来控制多线程修改全局变量的值。在实际的应用中,您可能还需要考虑其他方面,如错误处理和性能优化等。

3. 信号量(Semaphore):

信号量是一种经典的线程同步机制,它可以用于控制对共享资源的访问。
在Linux中,可以使用sem_t类型的信号量来实现线程同步。

在Linux下,我们可以使用信号量来实现对多线程修改全局变量的值的控制。信号量是一种用于进程间同步和互斥的机制,可以用来控制对共享资源的访问。

信号量可以分为二进制信号量计数信号量。二进制信号量只能取0或1,用于互斥操作。计数信号量可以取多个非负整数值,用于同步操作。

下面是一个简单的示例代码,实现了两个线程对全局变量进行自增操作的互斥控制:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>int global_var = 0;
sem_t sem;void* thread_func(void* arg) {int i;for (i = 0; i < 100000; i++) {sem_wait(&sem); // 等待信号量,若为0则阻塞global_var++;sem_post(&sem); // 释放信号量,唤醒等待的线程}return NULL;
}int main() {pthread_t thread1, thread2;sem_init(&sem, 0, 1); // 初始化信号量,初始值为1pthread_create(&thread1, NULL, thread_func, NULL);pthread_create(&thread2, NULL, thread_func, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);sem_destroy(&sem); // 销毁信号量printf("Global variable value: %d\n", global_var);return 0;
}

在上面的示例中,我们首先通过 sem_init 函数初始化了一个计数信号量 sem,初始值为1。然后创建了两个线程,并通过 pthread_create 函数将其与 thread_func 函数绑定。thread_func 函数中通过 sem_wait 函数等待信号量,当信号量的值为0时则阻塞,否则减1并继续执行。在对全局变量进行自增操作后,通过 sem_post 函数释放信号量,唤醒等待的线程。最后,通过 sem_destroy 函数销毁信号量。

运行该程序,两个线程会对全局变量 global_var 进行自增操作,由于信号量的存在,每次只能有一个线程能够修改该变量,从而实现了对全局变量访问的互斥控制。最终输出的全局变量值应为 200000。

需要注意的是,信号量的使用需要谨慎,错误的使用可能导致死锁等问题。确保在必要的时候对信号量加锁和解锁,并根据实际需求选择合适的信号量类型。


这些线程同步机制都可以通过Linux提供的pthread库来使用。在实际编程中,选择合适的线程同步机制取决于具体的应用场景和需求,以确保线程间的安全访问和协调。


拓展:
在 Linux 中编译依赖 pthread 库的程序,可以使用以下命令行表达式来编译:

gcc -o output_file source_file.c -lpthread

其中,output_file 是编译后生成的可执行文件的文件名,source_file.c 是需要编译的源代码文件的文件名。

选项 -lpthread 表示链接 pthread 库,将其加入到编译过程中。

如果源文件有多个,可以将它们一一列出来,例如:

gcc -o output_file source_file1.c source_file2.c -lpthread

这篇关于Linux和windows进程同步与线程同步那些事儿(三): Linux线程同步详解示例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/591336

相关文章

基于Linux的ffmpeg python的关键帧抽取

《基于Linux的ffmpegpython的关键帧抽取》本文主要介绍了基于Linux的ffmpegpython的关键帧抽取,实现以按帧或时间间隔抽取关键帧,文中通过示例代码介绍的非常详细,对大家的学... 目录1.FFmpeg的环境配置1) 创建一个虚拟环境envjavascript2) ffmpeg-py

python使用库爬取m3u8文件的示例

《python使用库爬取m3u8文件的示例》本文主要介绍了python使用库爬取m3u8文件的示例,可以使用requests、m3u8、ffmpeg等库,实现获取、解析、下载视频片段并合并等步骤,具有... 目录一、准备工作二、获取m3u8文件内容三、解析m3u8文件四、下载视频片段五、合并视频片段六、错误

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

在Windows上使用qemu安装ubuntu24.04服务器的详细指南

《在Windows上使用qemu安装ubuntu24.04服务器的详细指南》本文介绍了在Windows上使用QEMU安装Ubuntu24.04的全流程:安装QEMU、准备ISO镜像、创建虚拟磁盘、配置... 目录1. 安装QEMU环境2. 准备Ubuntu 24.04镜像3. 启动QEMU安装Ubuntu4

mysql中insert into的基本用法和一些示例

《mysql中insertinto的基本用法和一些示例》INSERTINTO用于向MySQL表插入新行,支持单行/多行及部分列插入,下面给大家介绍mysql中insertinto的基本用法和一些示例... 目录基本语法插入单行数据插入多行数据插入部分列的数据插入默认值注意事项在mysql中,INSERT I

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2