创建线程 ---- 实例

1、C语言 创建线程 执行2个不同的函数:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>// 第一个线程要执行的函数
void* function1(void* arg) {printf("Function 1 is running\n");// 执行一些任务...return NULL;
}// 第二个线程要执行的函数
void* function2(void* arg) {printf("Function 2 is running\n");// 执行一些任务...return NULL;
}int main() {pthread_t thread1, thread2;// 创建第一个线程执行function1if (pthread_create(&thread1, NULL, function1, NULL) != 0) {perror("Failed to create thread 1");return EXIT_FAILURE;}// 创建第二个线程执行function2if (pthread_create(&thread2, NULL, function2, NULL) != 0) {perror("Failed to create thread 2");return EXIT_FAILURE;}// 等待第一个线程结束if (pthread_join(thread1, NULL) != 0) {perror("Failed to join thread 1");return EXIT_FAILURE;}// 等待第二个线程结束if (pthread_join(thread2, NULL) != 0) {perror("Failed to join thread 2");return EXIT_FAILURE;}printf("Both threads have finished\n");return EXIT_SUCCESS;
}

2、C 创建两个线程 通过传递数组 执行同一个函数 打印数组的内容:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 线程要执行的函数,接受一个void*类型的参数,这里参数是一个指向整型数组的指针
void* print_array(void* arg) {int* array = (int*)arg;int size = 5;printf("Array contents: ");for (int i = 0; i < size; ++i) {printf("%d ", array[i]);}printf("\n");return NULL;
}int main() {pthread_t thread1, thread2;int array1[] = {1, 2, 3, 4, 5};int array2[] = {6, 7, 8, 9, 10};// 创建第一个线程,传递array1作为参数if (pthread_create(&thread1, NULL, print_array, (void*)array1) != 0) {perror("Failed to create thread 1");return EXIT_FAILURE;}// 创建第二个线程,传递array2作为参数if (pthread_create(&thread2, NULL, print_array, (void*)array2) != 0) {perror("Failed to create thread 2");return EXIT_FAILURE;}// 等待第一个线程结束if (pthread_join(thread1, NULL) != 0) {perror("Failed to join thread 1");return EXIT_FAILURE;}// 等待第二个线程结束if (pthread_join(thread2, NULL) != 0) {perror("Failed to join thread 2");return EXIT_FAILURE;}printf("Both threads have finished\n");return EXIT_SUCCESS;
}

3、C 创建两个线程 访问一个全局变量:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 全局变量
int global_variable = 0;// 互斥锁
pthread_mutex_t lock;// 线程要执行的函数
void* increment(void* arg) {// 锁定互斥锁pthread_mutex_lock(&lock);// 访问和修改全局变量:实际上是对锁进行操作,把内容放在 锁->内容ops->解锁 中// 这里可以加上 内核那本书里面的设计与实现 什么时候需要加锁!global_variable++;printf("Global variable incremented to: %d\n", global_variable);// 解锁互斥锁pthread_mutex_unlock(&lock);return NULL;
}int main() {pthread_t thread1, thread2;// 初始化互斥锁if (pthread_mutex_init(&lock, NULL) != 0) {perror("Failed to initialize mutex");return EXIT_FAILURE;}// 创建两个线程if (pthread_create(&thread1, NULL, increment, NULL) != 0) {perror("Failed to create thread 1");return EXIT_FAILURE;}if (pthread_create(&thread2, NULL, increment, NULL) != 0) {perror("Failed to create thread 2");return EXIT_FAILURE;}// 等待两个线程结束pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 销毁互斥锁pthread_mutex_destroy(&lock);printf("Final value of global variable: %d\n", global_variable);return EXIT_SUCCESS;
}

读取-修改竞态条件(Read-Modify-Write Race Condition):当一个线程正在读取变量的值时,另一个线程可能会修改这个变量。如果第一个线程在读取过程中第二个线程改变了变量的值,第一个线程可能会得到一个不一致的值。

内存可见性问题:在某些编译器和处理器优化下,没有锁的保护可能导致一个线程看不到另一个线程对共享变量所做的修改,因为编译器和处理器可能会对内存访问进行重排序。

数据依赖性问题:如果shared_data的值依赖于程序中的其他状态,并且这些状态可能被其他线程修改,那么即使只是读取shared_data,也需要确保在读取时这些依赖状态不会被改变。

为了保证线程安全和数据的一致性,即使是读取操作,也应该在修改和读取共享变量时使用互斥锁。这样可以确保在任何时候只有一个线程能够访问共享变量,无论是读取还是写入。

在实际应用中,如果性能是一个关键考虑因素,并且读操作远远多于写操作,可以考虑使用其他同步机制,如 读写锁(read-write lock),它允许多个线程同时读取,但在写入时仍然保证互斥。 然而,这仍然需要仔细设计以避免潜在的死锁和性能问题。对于简单的用例或者写操作较为频繁的情况,使用互斥锁通常是最直接和安全的方法。

4、C 创建两个线程 读写一个全局变量:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>// 全局变量
int shared_data = 0;// 互斥锁
pthread_mutex_t mutex;// 读取全局变量的线程函数
void* reader(void* arg) {int data;pthread_mutex_lock(&mutex);data = shared_data;pthread_mutex_unlock(&mutex);printf("Reader thread read data: %d\n", data);return NULL;
}// 修改全局变量的线程函数
void* writer(void* arg) {pthread_mutex_lock(&mutex);shared_data = *(int*)arg;pthread_mutex_unlock(&mutex);printf("Writer thread wrote data: %d\n", shared_data);return NULL;
}int main() {pthread_t reader_thread, writer_thread;int new_data = 42;// 初始化互斥锁if (pthread_mutex_init(&mutex, NULL) != 0) {perror("Failed to initialize mutex");return EXIT_FAILURE;}// 创建读取线程if (pthread_create(&reader_thread, NULL, reader, NULL) != 0) {perror("Failed to create reader thread");return EXIT_FAILURE;}// 创建写入线程if (pthread_create(&writer_thread, NULL, writer, (void*)&new_data) != 0) {perror("Failed to create writer thread");return EXIT_FAILURE;}// 等待线程结束pthread_join(reader_thread, NULL);pthread_join(writer_thread, NULL);// 销毁互斥锁pthread_mutex_destroy(&mutex);return EXIT_SUCCESS;
}

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

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

相关文章

使用mybatisplus的逆向工程自动生成数据库中表对应的实体类、mapper、service、serviceImpl、controller等文件

使用mybatisplus的逆向工程自动生成数据库中表对应的实体类、mapper、service、serviceImpl、controller等文件 详细流程如下&#xff1a; 1、引入依赖 <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-sta…

Linux介绍与安装CentOS 7操作系统

什么是操作系统 操作系统&#xff0c;英⽂名称 Operating System&#xff0c;简称 OS&#xff0c;是计算机系统中必不 可少的基础系统软件&#xff0c;它是 应⽤程序运⾏以及⽤户操作必备的基础环境 ⽀撑&#xff0c;是计算机系统的核⼼。 操作系统的作⽤是管理和控制计算机系…

【Linux】深入理解进程信号机制:信号的产生、捕获与阻塞

&#x1f3ac; 个人主页&#xff1a;谁在夜里看海. &#x1f4d6; 个人专栏&#xff1a;《C系列》《Linux系列》《算法系列》 ⛰️ 时间不语&#xff0c;却回答了所有问题 目录 &#x1f4da;前言 &#x1f4da;一、信号的本质 &#x1f4d6;1.异步通信 &#x1f4d6;2.信…

【西门子PLC.博途】——面向对象编程及输入输出映射FC块

当我们做面向对象编程的时候&#xff0c;需要用到输入输出的映射。这样建立的变量就能够被复用&#xff0c;从而最大化利用了我们建立的udt对象。 下面就来讲讲映射是什么。 从本质上来说&#xff0c;映射就是拿实际物理对象对应程序虚拟对象&#xff0c;假设程序对象是I0.0&…

WebRTC服务质量(04)- 重传机制(01) RTX NACK概述

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

MySQL索引的理解

MySQL与磁盘的交互 根据冯诺依曼结构体系&#xff0c;我们知道我们任何上层的应用想要去访问磁盘就必须要通过内存来访问&#xff0c;MySQL作为一款储存数据的服务&#xff0c;肯定是很多时间要用来访问磁盘。而大量访问磁盘一定会影响运行效率的在innoDB的存储引擎下为了减少…

spring集成ehcache

目录 一、前言二、使用ehcache注解方式2.1、配置2.2、使用示例三、直接读取xml方式3.1、配置3.2、使用示例3.3、结果说明一、前言 问题背景:一些业务场景中,一些数据往往是长期不变更,但数据使用较多。为了满足系统性能需要,可以借助本地缓存去使用,保证同一个JVM实例只保…

分布式全文检索引擎ElasticSearch-数据的写入存储底层原理

一、数据写入的核心流程 当向 ES 索引写入数据时&#xff0c;整体流程如下&#xff1a; 1、客户端发送写入请求 客户端向 ES 集群的任意节点&#xff08;称为协调节点&#xff0c;Coordinating Node&#xff09;发送一个写入请求&#xff0c;比如 index&#xff08;插入或更…

前端解析超图的iserver xml

前端解析超图的iserver xml const res await axios.get(url)const xmlDom new DOMParser().parseFromString(res.data, text/xml);// 获取versionconst version xmlDom.getElementsByTagNameNS(*, ServiceTypeVersion)[0].textContent// 获取layerconst layerDom xmlDom.ge…

Maven 生命周期

文章目录 Maven 生命周期- Clean 生命周期- Build 生命周期- Site 生命周期 Maven 生命周期 Maven 有以下三个标准的生命周期&#xff1a; Clean 生命周期&#xff1a; clean&#xff1a;删除目标目录中的编译输出文件。这通常是在构建之前执行的&#xff0c;以确保项目从一个…

Android Studio AI助手---Gemini

从金丝雀频道下载最新版 Android Studio&#xff0c;以利用所有这些新功能&#xff0c;并继续阅读以了解新增内容。 Gemini 现在可以编写、重构和记录 Android 代码 Gemini 不仅仅是提供指导。它可以编辑您的代码&#xff0c;帮助您快速从原型转向实现&#xff0c;实现常见的…

倒排单词C++

描述 编写程序&#xff0c;读入一行英文(只包含字母和空格&#xff0c;单词间以单个空格分隔)&#xff0c;将所有单词的顺序倒排并输出&#xff0c;依然以单个空格分隔。 输入描述 输入为一个字符串&#xff08;字符串长度至多为100&#xff09;。 输出描述 共一行&#xff0c;…

#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍04-盲SQL注入(Blind SQL Injection)

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

Scala 的迭代器

迭代器定义&#xff1a;迭代器不是一种集合&#xff0c;它是一种用于访问集合的方法。 迭代器需要通过集合对应的迭代器调用迭代器的方法来访问。 支持函数式编程风格&#xff0c;便于链式操作。 创建一个迭代器&#xff0c;相关代码如下&#xff1a; object Test {def mai…

Spring整合Redis基本操作步骤

Spring 整合 Redis 操作步骤总结 1. 添加依赖 首先&#xff0c;在 pom.xml 文件中添加必要的 Maven 依赖。Redis 相关的依赖包括 Spring Boot 的 Redis 启动器和 fastjson&#xff08;如果需要使用 Fastjson 作为序列化工具&#xff09;&#xff1a; <!-- Spring Boot Re…

底层理论基础(单片机)

计算机基础 IO逻辑 计算机系统中的高低电平逻辑1和0&#xff0c;数据在计算机中的存储、传输、运算都是以二进制形式进行的。 数据的传输通过总线真正传递的是电信号&#xff0c;高低电平&#xff08;0、1&#xff09;。运算在电路中进行&#xff0c;集成电路中运算。 计算机的…

深入浅出支持向量机(SVM)

1. 引言 支持向量机&#xff08;SVM, Support Vector Machine&#xff09;是一种常见的监督学习算法&#xff0c;广泛应用于分类、回归和异常检测等任务。自1990年代初期由Vapnik等人提出以来&#xff0c;SVM已成为机器学习领域的核心方法之一&#xff0c;尤其在模式识别、文本…

docker安装Redis、docker使用Redis、docker离线安装redis、Redis离线安装

服务器到期了&#xff0c;换了一个新的环境要重搭&#xff0c;就记录一下好了&#xff1a; -----docker在线安装Redis 拉取 Redis 镜像 docker pull redis:6.2 运行 Redis 容器 docker run --name redis -d redis docker run --name redis -d redis:6.2 映射端口 docker run -…

初探Java的双冒号运算符

什么是双冒号运算符 双冒号运算符 :: 是在 Java 8 中实现的一个新特性——方法引用。它能使用我们将方法作为一个参考传递到其他的方法中。它能将简化超级长的代码&#xff0c;提高代码可读性。 基本格式&#xff1a; ClassName::methodName双冒号运算符不会调用方法&#x…

B站bilibili视频转文字字幕下载方法

本文将讲述介绍一种使用本地工具如何快速的下载B站的字幕为本地文本文件的方法。 通常获取B站字幕需要在浏览器中安装第三方插件&#xff0c;通过插件获取字幕。随着大模型&#xff0c;生成式AI&#xff0c;ChatGPT的应用&#xff0c;B站也提供了AI小助手对视频的内容进行总结…