如何进行并发编程和线程同步?

并发编程是一种多任务处理的编程范式,它允许程序中的多个任务(线程、进程等)在相同的时间段内执行。线程同步是确保这些并发任务在共享资源上正确协作的一种技术。在C语言中,通过使用线程和相关的同步机制,可以实现并发编程和线程同步。本文将深入讨论并发编程的基本概念、C语言中的线程以及线程同步的原理和方法。

并发编程的基本概念

1. 并发和并行的区别

在讨论并发编程之前,我们需要理解并发和并行的概念。

  • 并发(Concurrency):指的是多个任务在相同的时间段内执行,但不一定是同时执行。在并发模型中,任务之间可能交替执行,通过时间片轮转或事件驱动的方式,从而创建一种看似同时执行的效果。

  • 并行(Parallelism):指的是多个任务在实际的同时执行,通常在多核处理器上。并行执行的任务彼此独立,可以同时处理不同的子任务。

并发编程是一种多任务处理的编程范式,它允许程序中的多个任务(线程、进程等)在相同的时间段内执行。线程同步是确保这些并发任务在共享资源上正确协作的一种技术。在C语言中,通过使用线程和相关的同步机制,可以实现并发编程和线程同步。本文将深入讨论并发编程的基本概念、C语言中的线程以及线程同步的原理和方法。

并发编程的基本概念

1. 并发和并行的区别

在讨论并发编程之前,我们需要理解并发和并行的概念。

  • 并发(Concurrency):指的是多个任务在相同的时间段内执行,但不一定是同时执行。在并发模型中,任务之间可能交替执行,通过时间片轮转或事件驱动的方式,从而创建一种看似同时执行的效果。

  • 并行(Parallelism):指的是多个任务在实际的同时执行,通常在多核处理器上。并行执行的任务彼此独立,可以同时处理不同的子任务。

C语言中的并发编程

在C语言中,要实现并发编程,最常用的方式是使用线程。线程是独立执行的代码单元,C语言提供了一些标准库函数来支持线程的创建、同步和销毁。

1. 线程创建和销毁

线程创建

在C语言中,线程的创建主要依赖于 <pthread.h> 头文件,该头文件提供了一组用于线程操作的函数。其中,pthread_create 函数用于创建新线程。

#include <pthread.h>void* threadFunction(void* arg) {// 线程的实际执行代码return NULL;
}int main() {pthread_t thread;int result = pthread_create(&thread, NULL, threadFunction, NULL);if (result == 0) {// 线程创建成功} else {// 线程创建失败}// 主线程的执行代码pthread_join(thread, NULL);  // 等待新线程结束return 0;
}

在上述示例中,pthread_create 函数创建了一个新线程,并指定了线程的执行函数 threadFunctionpthread_join 函数用于等待新线程结束。在实际应用中,需要注意线程的错误处理,以确保线程创建成功。

线程销毁

线程可以通过 pthread_exit 函数退出,也可以由主线程调用 pthread_cancel 函数来取消。值得注意的是,线程的退出不会自动释放其占用的资源,需要主动调用 pthread_join 来等待线程结束,并确保资源得到释放。

2. 线程同步

线程同步是确保多个线程之间正确协作的关键。在并发编程中,有多种线程同步的机制,常见的包括互斥锁、条件变量、信号量等。

互斥锁(Mutex)

互斥锁是一种用于保护共享资源不被多个线程同时访问的机制。在C语言中,可以使用 <pthread.h> 头文件中的互斥锁相关函数来实现互斥锁。

#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* threadFunction(void* arg) {pthread_mutex_lock(&mutex);  // 上锁// 临界区代码pthread_mutex_unlock(&mutex);  // 解锁return NULL;
}int main() {pthread_t thread1, thread2;pthread_create(&thread1, NULL, threadFunction, NULL);pthread_create(&thread2, NULL, threadFunction, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);return 0;
}

在上述示例中,pthread_mutex_lock 用于上锁,保护临界区代码,而 pthread_mutex_unlock 用于解锁。互斥锁的正确使用可以防止多个线程同时进入临界区,从而保护共享资源的一致性。

条件变量(Condition Variable)

条件变量用于在多线程中等待某个特定条件的发生。它通常与互斥锁一起使用,以确保在检查条件和等待之间的操作是原子的。

#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition = PTHREAD_COND_INITIALIZER;
int sharedData = 0;void* producerFunction(void* arg) {// 生成数据pthread_mutex_lock(&mutex);// 更新共享资源sharedData = 42;// 通知等待的消费者线程pthread_cond_signal(&condition);pthread_mutex_unlock(&mutex);return NULL;
}void* consumerFunction(void* arg) {pthread_mutex_lock(&mutex);// 等待条件发生while (sharedData == 0) {pthread_cond_wait(&condition, &mutex);}// 处理共享资源int data = sharedData;pthread_mutex_unlock(&mutex);// 使用数据return NULL;
}int main() {pthread_t producer, consumer;pthread_create(&producer, NULL, producerFunction, NULL);pthread_create(&consumer, NULL, consumerFunction, NULL);pthread_join(producer, NULL);pthread_join(consumer, NULL);return 0;
}

在上述示例中,pthread_cond_wait 用于等待条件的发生,而 pthread_cond_signal 用于通知等待的线程。条件变量的使用可以实现线程之间的协作,确保数据的正确同步。

信号量(Semaphore)

信号量是一种用于控制对共享资源的访问的机制。在C语言中,可以使用 <semaphore.h> 头文件中的信号量相关函数来实现信号量。

#include <semaphore.h>
#include <pthread.h>sem_t semaphore;void* threadFunction(void* arg) {sem_wait(&semaphore);  // 等待信号量// 临界区代码sem_post(&semaphore);  // 释放信号量return NULL;
}int main() {sem_init(&semaphore, 0, 1);  // 初始化信号量pthread_t thread1, thread2;pthread_create(&thread1, NULL, threadFunction, NULL);pthread_create(&thread2, NULL, threadFunction, NULL);pthread_join(thread1, NULL);pthread_join(thread2, NULL);sem_destroy(&semaphore);  // 销毁信号量return 0;
}

在上述示例中,sem_wait 用于等待信号量,而 sem_post 用于释放信号量。信号量的值可以用于控制对共享资源的访问,确保不会有过多的线程同时访问。

并发编程的最佳实践

并发编程是一个复杂的领域,需要注意一些最佳实践以确保程序的正确性和性能。

  1. 避免竞争条件:竞争条件是多个线程试图同时修改共享资源而导致的问题。使用互斥锁等同步机制来保护共享资源,避免竞争条件的发生。

  2. 尽量减小临界区:临界区是指在其中访问共享资源的代码段。尽量减小临界区的长度,以减少线程间的竞争,提高程序的并发性能。

  3. 避免死锁:死锁是指多个线程因为互相等待对方释放资源而无法继续执行的情况。使用良好设计的同步机制和避免循环等待可以减少死锁的发生。

  4. 尽量避免使用全局变量:全局变量容易导致线程之间的耦合,增加了程序的复杂性。尽量使用局部变量,或者使用同步机制来保护全局变量的访问。

  5. 使用无锁数据结构:无锁数据结构是一种不需要互斥锁的数据结构,通过一些原子操作来确保多线程并发访问的正确性。在高并发场景下,使用无锁数据结构可能提供更好的性能。

  6. 使用线程池:线程池是一种管理和重用线程的机制,可以提高线程的利用率和降低线程创建销毁的开销。

  7. 测试和调试:并发程序中的错误往往难以调试和复现。进行充分的测试,包括单元测试、集成测试和性能测试,以确保并发程序的正确性和稳定性。

  8. 考虑性能优化:并发编程的性能可能受限于线程之间的同步开销。在一些情况下,通过使用更高级的同步机制、无锁数据结构或者调整线程池的大小等手段进行性能优化。

结论

并发编程是一项复杂的任务,要求程序员充分理解多线程编程的概念和技术。

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

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

相关文章

5款免费BI数据可视化工具,2023年最新精选推荐!

BI可视化工具顾名思义是进行数据分析和可视化的软件&#xff0c;旨在将数据以表格、图表、仪表盘等形式展示出来&#xff0c;让用户能够更加直观了解其业务状况、发现问题&#xff0c;并在必要时进行决策。   市面上BI数据可视化工具很多&#xff0c;目前比较火的像国外的Tabl…

应用软件安全编程--24不要使用硬编码密匙

当程序中使用硬编码加密密匙时&#xff0c;所有项目开发人员都可以查看该密匙&#xff0c;甚至如果攻击者能够获取 程序 class文件&#xff0c;可通过反编译得到密匙&#xff0c;硬编码加密密匙会大大降低系统安全性。 对于避免使用硬编码密匙的情况&#xff0c;示例1给出了不…

jQUery(基本介绍+示例代码)

一、JQUery基本介绍和特点 jQuery 是一个快速、轻量级、跨浏览器的 JavaScript 库。它简化了在网页开发中处理诸多任务的过程&#xff0c;提供了易于使用的 API&#xff0c;使得开发者能够更容易地操作 HTML 文档、处理事件、执行动画、发送 AJAX 请求等。 以下是一些 jQuery…

CTF/AWD竞赛标准参考书+实战指南

随着网络安全问题日益凸显&#xff0c;国家对网络安全人才的需求持续增长&#xff0c;其中&#xff0c;网络安全竞赛在国家以及企业的人才培养和选拔中扮演着至关重要的角色。 在数字化时代&#xff0c;企业为了应对日益增长的攻击威胁&#xff0c;一般都在大量部署安全产品、…

PyInstaller 如何 将第三方库打包到可执行文件

PyInstaller 是一个非常流行的 Python 打包工具&#xff0c;它可以将你的 Python 程序以及其依赖项打包成一个可执行文件。如果你想将第三方库打包到可执行文件中&#xff0c;你可以按照以下步骤操作&#xff1a; 首先&#xff0c;确保你已经安装了 PyInstaller。如果没有&…

uview-plus u-picker的defaultIndexs修改后无效的问题

uniapp项目中使用了uview-plus组件库&#xff0c;在使用u-picker组件时&#xff0c;发现其默认的选中属性 defaultIndex是一次性的&#xff0c;修改后无法响应&#xff0c;解决办法就是在u-picker源码中修改这个属性的watch,源码位置在uni_modules/uview-plus/components/u-pi…

Hive 定义变量 变量赋值 引用变量

Hive 定义变量 变量赋值 引用变量 变量 hive 中变量和属性命名空间 命名空间权限描述hivevar读写用户自定义变量hiveconf读写hive相关配置属性system读写java定义额配置属性env只读shell环境定义的环境变量 语法 Java对这个除env命名空间内容具有可读可写权利&#xff1b; …

Qt如何解析JSON格式

Qt 5.15 版本以后&#xff0c;推荐使用 QJsonDocument 来解析 JSON 数据。 直接贴代码&#xff1a; #include <QJsonDocument> #include <QJsonObject> #include <QFile>// 从文件中读取 JSON 数据 QFile file("data.json"); file.open(QIODevi…

SQL零基础入门教程,贼拉详细!贼拉简单! 速通数据库期末考!(十一)

COUNT() 计数函数 COUNT() 函数返回匹配指定条件的行数。 语法&#xff1a; 1.返回指定列的字段值条数 SELECT COUNT(column_name) FROM table_name;2.返回整表数据行条数 SELECT COUNT(*) FROM table_name;3.返回指定列去重后的字段值条数 SELECT COUNT(DISTINCT column_…

Leetcode 第 372 场周赛题解

Leetcode 第 372 场周赛题解 Leetcode 第 372 场周赛题解题目1&#xff1a;2937. 使三个字符串相等思路代码复杂度分析 题目2&#xff1a;2938. 区分黑球与白球思路代码复杂度分析 题目3&#xff1a;2939. 最大异或乘积思路代码复杂度分析 题目4&#xff1a;2940. 找到 Alice 和…

vatee万腾的科技奇点:Vatee创新力引领数字未来

在数字时代的涌动潮流中&#xff0c;Vatee万腾显露出一颗科技的奇点之心&#xff0c;其创新力正引领着数字未来的前沿。随着科技不断演进&#xff0c;Vatee万腾敏锐地捕捉到了科技的契机&#xff0c;展现出独特的创新视野&#xff0c;为数字化未来勾勒出了一幅令人瞩目的画卷。…

使用frp搭建内网穿透服务

使用frp搭建内网穿透服务 frp 是一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c;且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。 1.下载frp 下载地址 2.服务端安装 …

[Linux] shell脚本相关知识

一、shell脚本基础 1.1 shell脚本的作用 shell将人类使用的高级语言翻译成二进制&#xff0c;再将二进制翻译成高级语言。换句话就是人类写了一个命令集合&#xff0c;然后用bash去翻译给硬件执行。 linux中常见的shell&#xff1a; bash:基于gun的框架下发展的shell csh:类…

同为科技(TOWE)智能机柜PDU助力上海华为数据中心完善机房末端配电

智能时代加速而来&#xff0c;最大的需求是算力&#xff0c;最关键的基础设施是数据中心。作为一家在信息通信领域拥有多年经验和技术积累的公司&#xff0c;华为在全国多个地区都设有数据中心&#xff0c;如知名的贵州贵安华为云全球总部、内蒙古乌兰察布华为数据中心等&#…

pnpm 管理依赖包是如何节省磁盘空间的?

npm 存在的问题 我们经常使用 npm 来管理 node 项目中的包&#xff0c;从 package.json 中读取配置将依赖下载到本地&#xff0c;以保障项目的正常运行。 当项目数量多时&#xff0c;这样的包管理方式会非常的占用电脑内存。由于每个项目都有属于自己的依赖&#xff0c;每个项…

什么是多域名证书?

多域名证书是指同一个证书中包含多个域名&#xff0c;能够在多个站点之间共享一份证书&#xff0c;实现一个站点对应多个域名的情况。多域名证书非常适合需要跨多个站点部署的应用&#xff0c;例如企业的子站点、博客等。 特点 多域名证书的优点包括以下几个方面&#xff1a;…

【软件工程_软件工程项目管理】课后题

选择 1、( A )不属于项目的活动。 A.罐头产品的生产 B.一种新型罐头产品的发展 C.罐头产品的试制 D.罐头产品的营销策划 2、WBS&#xff08;任务分解结构&#xff09;非常重要&#xff0c;因为下列原因&#xff0c;除了&#xff08;D &#xff09; A.帮助组织工作 B.防止遗漏工…

python使用timm创建模型出现connect error

使用timm创建模型会出现网络连接等错误&#xff0c;比如LocalEntryNotFoundError: Connection error, and we cannot find the requested files in the disk cache. Please try again or make sure your Internet connection is on. 这是因为timm下载权重默认是从huggingfaceH…

【原创】为MybatisPlus增加一个逻辑删除插件,让XML中的SQL也能自动增加逻辑删除功能

前言 看到这个标题有人就要说了&#xff0c;D哥啊&#xff0c;MybatisPlus不是本来就有逻辑删除的配置吗&#xff0c;比如TableLogic注解&#xff0c;配置文件里也能添加如下配置设置逻辑删除。 mybatis-plus:mapper-locations: classpath*:mapper/*.xmlconfiguration:mapUnd…

品牌挑选控价服务商的标准参考

控价是一项需要投入时间精力的工作&#xff0c;品牌可以自主团队去做&#xff0c;但如果涉及数据量太大的时候&#xff0c;还需要开发系统&#xff0c;这样显然会增加非常多的成本&#xff0c;系统开发费用和运维费用都是一笔不小的开支&#xff0c;所以现在很多的品牌会选择找…