Linux系统应用编程(四)Linux多线程

news2024/12/28 20:01:51

本篇文章主要内容:

    • Linux系统应用编程(四)Linux多线程
    • 一、线程和进程的区别
    • 二、Linux多线程
      • 1.线程的使用 - 创建、退出、等待
      • 2.线程的同步 - 互斥量
        • (1)互斥量的理解(略)
        • (2)互斥量的使用
        • (3)死锁
      • 3.线程间通信- 条件变量
        • (1)条件变量的理解
        • (2)条件变量的使用

Linux系统应用编程(四)Linux多线程

一、线程和进程的区别

  • 进程是静态的程序/代码,在操作系统分配的资源下运行起来用于完成特定任务的动态程序,简单说就是代码在操作系统上跑起来/运行起来就是一个进程。这个过程中,操作系统会为进程分配独立的地址空间,每个进程之间相互独立;
  • 线程是进程的一条执行路径,只有独立的堆栈和局部变量,没有独立的地址空间,且线程共享进程的资源。可以说,进程是操作系统分配资源的基本单元,线程是进程执行过程中的一个单元。
  • 线程相比于进程,线程之间实现通信,共享数据更方便,不需要像进程间通信使用额外的机制;线程运行切换速度快,开销小,比进程的响应速度快,更轻量级。

二、Linux多线程

1.线程的使用 - 创建、退出、等待

在这里插入图片描述

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

/* 主线程:遍历100内奇数 */
/* 子线程:遍历100内偶数 */
/* 主线程等待子线程退出后,输出其退出返回值 */

void *threadRun(void *pretn){
    static int i = 0;
    for(i=0;i<=100;i++){
        if(i%2 == 0)printf("subThread:%d\n",i);
    }
    pthread_exit(pretn);
}

int main(){

    pthread_t thread1;
    int arg = 2023;
    void *ptemp = &arg;
    pthread_create(&thread1,NULL,threadRun,ptemp);

    for(int i=0;i<=100;i++){
        if(i%2 != 0)printf("Main:%d\n",i);
    }
    void *p = NULL;
    pthread_join(thread1,&p);
    printf("subThread return value: %d\n",*(int *)p);
    return 0;
}

在这里插入图片描述

2.线程的同步 - 互斥量

  • 经典同步问题:银行储户取钱(C语言版,Java版储户存钱见Java多线程 7.编程练习)
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

/* 银行账户 */
typedef struct Account {
    int balance;		//余额
    int (*dramMoney)(int *,int);	//取钱方法
    int (*saveMoney)(int *,int);	//存钱方法(本例未实现)
}Account;


/* 取钱方法实现 */
int dramMoney(int *bal,int cash){
    while(*bal>0 && cash>0){	//余额,取钱金额大于0,可以取钱
        usleep(20*1000);	//由于未进行同步,即使进行条件判断,也会出现错误
        *bal -= cash;		//取钱:余额=余额-取出的金额
        printf("(tid=%ld)Dram Money:%d$ succeed,now balance:%d$\n",pthread_self(),cash,*bal);
    }
    return *bal;
}

/* 客户取钱(一个线程=一个客户) */
void *customer(void *acc){
    Account *ptmp =  (Account *)acc;
    ptmp->dramMoney(&ptmp->balance,1000);
    pthread_exit(acc);
}

int main(){
	
    /* 初始化:账户里有18000 */
    Account *acc = (Account *)malloc(sizeof(Account));
    acc->balance = 18000;
    acc->dramMoney = dramMoney;

    /* 创建两个线程模拟两个客户同时取钱 */
    pthread_t t1,t2;
    pthread_create(&t1,NULL,customer,acc);
    pthread_create(&t2,NULL,customer,acc);

    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    return 0;
}

在这里插入图片描述

  • 可以看到,出现了线程安全问题。接下来使用互斥量对其进行修改

(1)互斥量的理解(略)

互斥量(mutex)本质上是一把锁,在访问共享资源前对互斥量进行加锁,访问完成后释放锁。加锁状态下,其他线程阻塞等待,防止多个线程同时访问相同的共享资源。

(2)互斥量的使用

在这里插入图片描述

  • 银行储户取款(同步版)
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

/* 银行账户 */
typedef struct Account {
    int balance;		//余额
    int (*dramMoney)(int *,int);	//取钱方法
    int (*saveMoney)(int *,int);	//存钱方法(本例未实现)
}Account;

pthread_mutex_t mutex;

/* 取钱方法实现 */
int dramMoney(int *bal,int cash){
    while(1){	//余额,取钱金额大于0,可以取钱
        pthread_mutex_lock(&mutex);
        if(*bal > 0) {			//如果未进行同步,即使进行条件判断,也会出现错误
            usleep(50 * 1000);
            *bal -= cash;        //取钱:余额=余额-取出的金额
            printf("(tid=%ld)Dram Money:%d$ succeed,now balance:%d$\n", pthread_self(), cash, *bal);
        }else{
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);
    }
    return *bal;
}

/* 客户取钱(一个线程=一个客户) */
void *customer(void *acc){
    Account *ptmp =  (Account *)acc;
    ptmp->dramMoney(&ptmp->balance,1000);
    pthread_exit(acc);
}

int main(){
    pthread_mutex_init(&mutex,NULL);
    /* 初始化:账户里有180000 */
    Account *acc = (Account *)malloc(sizeof(Account));
    acc->balance = 180000;	
    acc->dramMoney = dramMoney;

    /* 创建两个线程模拟两个客户同时取钱 */
    pthread_t t1,t2;
    pthread_create(&t1,NULL,customer,acc);
    pthread_create(&t2,NULL,customer,acc);

    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    pthread_mutex_destroy(&mutex);
    return 0;
}

PS:原先设置账户余额1800,发现cpu速度太快第二个线程还没抢到锁运行就结束,改成18万就能看到线程切换了 如果是ubuntu虚拟机,把cpu设置成1核就可以看到线程切换运行了,前面发现只有单线程再跑,还以为是代码有问题

(3)死锁

死锁是指在多进程或多线程下,由于进程/线程之间竞争获取共享资源,导致进程/线程间彼此都相互等待对方释放所持有的资源,使程序所有线程处于无法继续执行的无限等待状态。<如何避免死锁?>规划设计好代码中线程对同步锁的操作,避免嵌套同步、也尽量减少同步资源的定义以避免出现死锁。

3.线程间通信- 条件变量

(1)条件变量的理解

​ 条件变量是Linux线程同步和线程通信的一种机制,条件变量可以使线程进入等待,也可以唤醒等待中的进程,以确定何时执行某些操作,例如等待某个资源的可用性;条件变量和互斥量配合使用,可以实现线程同步(线程安全)的线程间通信,也可以解决某个线程长时间得不到锁处于等待状态(线程饥饿)。例如:在多线程环境中实现线程安全的线程间通信,避免同一时间的并发访问共享资源。

(2)条件变量的使用

用法上很像Java的wait()、notify()实现线程间通信的方法。

  • 银行储户取钱(使用条件变量+互斥量实现两个储户交替取钱)
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

/* 银行账户 */
typedef struct Account {
    int balance;		//余额
    int (*dramMoney)(int *,int);	//取钱方法
    int (*saveMoney)(int *,int);	//存钱方法(本例未实现)
}Account;

pthread_mutex_t mutex;
pthread_cond_t cond;

/* 取钱方法实现 */
int dramMoney(int *bal,int cash){
    while(1){	//余额,取钱金额大于0,可以取钱
        pthread_mutex_lock(&mutex);
        pthread_cond_signal(&cond);
        if(*bal > 0) {
            usleep(50 * 1000);    //由于未进行同步,即使进行条件判断,也会出现错误
            *bal -= cash;        //取钱:余额=余额-取出的金额
            printf("(tid=%ld)Dram Money:%d$ succeed,now balance:%d$\n", pthread_self(), cash, *bal);

            /* 取完钱等待并释放锁给另一个线程;另一个线程得到锁就上锁再唤醒它,依次循环实现交替执行 */
            pthread_cond_wait(&cond,&mutex);	
            pthread_mutex_unlock(&mutex);
        }else{
            pthread_mutex_unlock(&mutex);
            break;
        }
    }
    return *bal;
}

/* 客户取钱(一个线程=一个客户) */
void *customer(void *acc){
    Account *ptmp =  (Account *)acc;
    ptmp->dramMoney(&ptmp->balance,1000);
    pthread_exit(acc);
}

int main(){
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    /* 初始化:账户里有90000 */
    Account *acc = (Account *)malloc(sizeof(Account));
    acc->balance = 9000;
    acc->dramMoney = dramMoney;

    /* 创建两个线程模拟两个客户同时取钱 */
    pthread_t t1,t2;
    pthread_create(&t1,NULL,customer,acc);
    pthread_create(&t2,NULL,customer,acc);

    pthread_join(t1,NULL);
    pthread_join(t2,NULL);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    return 0;
}

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

你真的会自动化测试?自动化测试技术选型抉择

自动化测试框架 在学习自动化测试或者实践自动化测试时&#xff0c;我们一定会对一个名词不陌生&#xff0c;那就是“自动化测试框架”&#xff0c;而有些人也将Selenium、Appium这样的工具也称之为“自动化测试框架”&#xff0c;那么到底自动化测试框架如何理解呢&#xff1…

多种文字翻译软件-翻译常用软件

整篇文档翻译软件 整篇文档翻译软件是一种实现全文翻译的自动翻译工具&#xff0c;它能够快速、准确地将整篇文档的内容翻译成目标语言。与单词、句子翻译不同&#xff0c;整篇文档翻译软件不仅需要具备准确的语言识别和翻译技术&#xff0c;还需要考虑上下文语境和文档格式等多…

【Linux】一文带你探究网络世界的基石

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;计算机网络…

JVM专题

JVM类加载 Java里有如下几种类加载器&#xff1a; 引导类加载器&#xff1a;负责加载支撑JVM运行的位于JRE的lib目录下的核心类库&#xff0c;比如 rt.jar、charsets.jar等 扩展类加载器&#xff1a;负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包应用程序…

一篇文章让你搞懂TypeScript中的??和?:和?.和!.是什么意思

TypeScript中的??和?:和?.和!.是什么意思&#xff1f;知识回调&#xff08;不懂就看这儿&#xff01;&#xff09;场景复现核心干货???:?.!.知识回调&#xff08;不懂就看这儿&#xff01;&#xff09; 知识专栏专栏链接TypeScript知识专栏https://blog.csdn.net/xsl_…

私有化部署GPT,告别网络困扰

最近的GPT是热火朝天&#xff0c;基本人手一个。工具用的好&#xff0c;工作5分钟&#xff0c;划水一整天。 不过最近Chat的访问越来越限制了&#xff0c;访问官网都有网络的问题&#xff0c;今天给大家介绍一个方案&#xff0c;私人独享属于自己的chat&#xff0c;不再担心想…

sdx12使能bluetooth

最后的效果&#xff1a; 1.驱动使能 apps_proc/kernel/msm-5.4/arch/arm/configs/vendor/sdxnightjar.config #add bt driver CONFIG_BTy CONFIG_MSM_BT_POWERy使用的芯片是sdx12 QCA6174A-1 管脚配置如下&#xff08;如果管脚不同&#xff0c;需要修改对应的dts&#xff09…

(十)排序算法-冒泡排序

1 排序算法 1.1 介绍 排序也称为排序算法&#xff08;Sort Algorithm&#xff09;&#xff0c;排序是将一组数据&#xff0c;依指定的顺序进行排列的过程。 1.2 排序的分类 &#xff08;1&#xff09;内部排序 指将需要处理的所有数据都加载到内部存储器中进行排序。 &…

C/C++程序设计——const关键字

1.修饰变量 1.1 作用 功能&#xff1a;不能直接被修改 const修饰变量&#xff0c;就相当于是定义了一个常量。该变量不能直接被修改&#xff0c;但是可以通过指针修改。 作用&#xff1a;便于维护、提前发现可能错误的修改 比如程序中大量使用了一个数字10&#xff0c;且不会…

GaussDB工作级开发者认证—第一章GaussDB数据库介绍

一. GaussDB概述 GaussDB是华为基于openGauss自研生态推出的企业级分布式关系型数据库。具备企业级复杂事物混合负载能力&#xff0c;同时支持分布式事务强一致性&#xff0c;同城跨AZ部署&#xff0c;数据0丢失&#xff0c;支持1000的计算节点扩展能力&#xff0c;4PB海量存储…

springcloud2.1.0整合seata1.5.2+nacos2.10(附源码)

springcloud2.1.0整合seata1.5.2nacos2.10&#xff08;附源码&#xff09; 1.创建springboot2.2.2springcloud2.1.0的maven父子工程如下&#xff0c;不过多描述&#xff1a; 搭建过程中也出现很多问题&#xff0c;主要包括&#xff1a; 1.seataServer.properties配置文件的组…

安全配置管理 (SCM):建立安全的基础

通过确保在端点中建立和维护理想的安全配置&#xff0c;让自己在安全的基础上做好准备&#xff0c;这样公司就不会因单个漏洞而分崩离析。安全配置管理涉及持续检测端点中各个组件之间的配置偏差和错误配置&#xff0c;并使它们重新对齐。 在本文中&#xff0c;将了解 Vulnera…

<Linux开发> linux应用开发-之-进程通信之管道例程

一、简介 所谓管道&#xff0c;是指用于连接一个读进程和一个写进程&#xff0c;以实现它们之间通信的共享文件&#xff0c;又称 pipe 文件。 向管道&#xff08;共享文件&#xff09;提供输入的发送进程&#xff08;即写进程&#xff09;&#xff0c;以字符流形式将大量的数…

Windows串口出厂测试工具与使用说明

WCHUsbSerTest是一款用于WCH USB转串口系列产品出厂测试的工具软件&#xff0c;方便用户对产品进行批量化功能测试。该软件支持以下特性&#xff1a; 支持设备热插拔检测&#xff0c;插入自动测试。支持两种测试模式&#xff1a;1个设备自测、2个设备互相连接测试。支持多种串…

VMware Horizon 8 2303 - 虚拟桌面基础架构 (VDI) 和应用软件

请访问原文链接&#xff1a;https://sysin.org/blog/vmware-horizon-8/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Version2303DocumentationRelease NotesRelease Date2023-03-30 虚拟桌面基础架构 (VDI) 和应用软件 VMw…

chagpt中文镜像版-ChatGPT工具下载

ChatGPT工具下载 ChatGPT是由OpenAI公司开发的预训练语言模型&#xff0c;目前已经开源并在GitHub上发布了相关代码和模型&#xff0c;提供了使用Python编写的API。如果您要使用ChatGPT&#xff0c;您可以通过以下步骤进行下载和安装&#xff1a; 在GitHub上下载&#xff1a;您…

【vue】 vue2 中使用 Tinymce 富文本编辑器

文章目录Tinymce 效果一、安装依赖二、封装组件-Tinymce.vue三、汉化文件-zh_CN.js四、vue使用组件封装五、整体目录结构六、可能会遇到的问题import "tinymce/icons/default" 路径找不到需要升级tinymce版本Tinymce 效果 一、安装依赖 npm i tinymce5.1.0 -S npm i…

计算机组成原理实验一(完整)

在VC中使用调试功能将下列语句运行的内存存放结果截图&#xff0c;每运行一句需截图一次。 #include<stdio.h> int main() {int a 你的学号末两位-100; //0x&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#x…

【Redis 进阶之路】3. Redis 主从 以及哨兵

Redis 主从 以及哨兵 单实例Redis 不足&#xff1a; 上述的是一个单实例的Redis。 我们可以先分析下有哪些不足&#xff1a; 单点故障 &#xff08;是每个单实例必须面对的问题&#xff09;容量有限 &#xff08;Redis毕竟是缓存型数据库&#xff0c;容量取决于服务器分配的容…

多目标优化算法评价指标(performance metrics)

参考Performance metrics in multi-objective optimization​​​​​​​ Riquelme, N., Lcken, C. V., & Baran, B. (2015, 19-23 Oct. 2015). Performance metrics in multi-objective optimization. Paper presented at the 2015 Latin American Computing Conference…