线程和进程延续

1.线程和进程启动终止方式 

1.创建子进程,子线程       

2.退出进程/线程

3.回收僵尸进程资源 / 回收线程资源

4.进程终止函数  /  线程清理函数

2.线程状态切换

pthread_create()变为就绪态,调度后成为运行态,pthread_join()成为阻塞态,从运行态运行完或者异常退出后进入线程结束

3.线程属性初始化和销毁

最重要的是线程分离状态属性,其他系统会根据调度自己设置

使用线程属性前,需要初始化,结束再销毁

1.设置和获得分离属性

1.detach(分离)  第一个函数是获得当前线程属性中的分离属性,第二个是设置线程的分离状态属性   

2. detachstate取值为PTHREAD_CREATE_JOINABLE  要在主线程调用pthread_join()系统资源才会释放

3.以分离状态启动的线程,在线程结束后会自动释放占有的系统资源

4.线程启动分离属性编程实战

pthread_join(id,  &)用于释放线程结束前相关资源

1.以正常状态启动需要调用pthread_join()

2.以分离状态启动线程不要调用pthread_join(),会出错,也不能利用这个函数获取子线程运行函数返回结果,分离的意思是主控线程于子线程分离开了

3.分离属性在网络通讯中使用的多,例如服务器要响应几百个客户端请求,启动很多个进程不合适,在服务器端启动多线程来处理服务器端的大并发客户端请求,来一个处理一个,处理完了自动释放资源。在服务器端如何如理客户端多并发处理请求,启动线程以分离状态启动,这是最优的方式

5.线程前章节回顾

6.线程同步和互斥

1.线程互斥

在全局变量使用,例如存款,一个线程存钱100万,还没存入被另外一个线程将存款金额修改为一万,这样导致存入只有一万,这样就涉及线程不安全,一个线程对共享资源操作时,其他线程就等待,其他线程按照系统优先级调度对共享资源进行访问和操作,这样是互斥的操作,线程的互斥,线程的执行是相互排斥的

利用以下技术达到线程互斥

2.线程同步

建立在线程互斥基础上,但也要考虑线程先后执行约束问题,后面线程必须等待前一个线程操作完毕,结果出来后,后面线程才能对这个结果进行操作

研发小组进行软件开发,测试小组对软件项目进行测试,类似两个线程,研发小组对软件开发好后,再对软件进行测试,这里包含线程互斥,包含线程相互执行的约束,等到研发小组对软件开发好后,测试小组再对共享资源进行操作,测试小组严重依赖与研发小组

3.线程互斥案例(银行ATM操作)

堆中

3.线程互斥锁(互斥量)

多个线程共享资源的场景使用,电话亭,进入电话亭打电话锁住(打完后开门其他人根据先后再进入)    同一时刻只能有一个线程拿到该锁     一个线程对共享资源加锁,其他线程视图上锁已经被锁的资源,将被挂起,直到拿到锁的线程解锁

互斥锁数据类型pthread_muxtex_t

互斥锁的创建和销毁

1.互斥锁初始化函数第二个参数,传入NULL,以默认的情况下创建默认互斥锁,是个标准互斥锁,所以一般情况下传入NULL就行

互斥锁上锁和解锁

pthread_mutex_lock()上锁,拿不到锁阻塞

pthread_mutex_trylock(),上锁,拿不到锁返回错误

对共享资源成功上锁到释放锁之间的区域叫做临界区

结构体中定义互斥锁与银行账户绑定

typedef struct{
    int code;  //账户账号
    double balance;

    //定义一把互斥锁
    //银行账户(共享资源),互斥锁

    /*
        建议互斥锁用来锁定一个账户,和账户绑定在一起,
        尽量不设置成全局变量,否则
        可能出现一把锁去锁几百个账户,导致并发性能降低
    */
    pthread_mutex_t mutex;
}Account;

account.h文件代码

#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__

#include <pthread.h>

typedef struct{
    int code;  //账户账号
    double balance;

    //定义一把互斥锁
    //银行账户(共享资源),互斥锁

    /*
        建议互斥锁用来锁定一个账户,和账户绑定在一起,
        尽量不设置成全局变量,否则
        可能出现一把锁去锁几百个账户,导致并发性能降低
    */
    pthread_mutex_t mutex;
}Account;

//创建账户
extern Account* create_account(int code, double balance);
//销毁账户
extern void destroy_account(Account *a);
//取款
extern double withdraw(Account *a, double amt);
//存款
extern double deposit(Account *a, double amt);
//查看账户余额
extern double get_balance(Account *a);


#endif

account.c代码


#include "account.h"
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>

//创建账户
Account* create_account(int code, double balance)
{
    //创建在堆中
    Account *a = (Account*)malloc(sizeof(Account));
    assert(a != NULL);  //()里面为bool类型,为假程序会就此结束
    a->code = code;
    a->balance = balance;

    //对互斥锁进行初始化
    pthread_mutex_init(&a->mutex, NULL);

    return a;
}
//销毁账户
void destroy_account(Account *a)
{
    assert(a != NULL);
    //销毁互斥锁
    pthread_mutex_destroy(&a->mutex);

    free(a);
}
//取钱
double withdraw(Account *a, double amt)
{
    assert(a != NULL);

    //从成功上锁到释放锁叫做临界区
    //加锁,对共享资源(账户)进行加锁,资源被占用则会阻塞
    pthread_mutex_lock(&a->mutex);

    if(amt < 0 || amt > a->balance){
        pthread_mutex_unlock(&a->mutex);
        return 0.0;
    }
    double balance = a->balance;

    //sleep(1)用来使这个线程延时让其他线程占用CPU取款,模拟情景
    sleep(1);  //取款操作有个过程,停顿一下,存取数据,读取数据

    balance -= amt;
    a->balance = balance; //银行账户余额

    //释放互斥锁
    pthread_mutex_unlock(&a->mutex);
    return amt; //取款成功返回取款金额
}
//存钱
double deposit(Account *a, double amt)
{
    assert(a != NULL);
    
    //上锁
    pthread_mutex_lock(&a->mutex);
    if(amt < 0){
        //解锁
        pthread_mutex_unlock(&a->mutex);
        return 0.0;
    }
    a->balance += amt;
    sleep(1);

    //解锁
    pthread_mutex_unlock(&a->mutex);
    
    return amt;
}
//查看账户余额
double get_balance(Account *a)
{
    assert(a != NULL);

    //上锁
    pthread_mutex_lock(&a->mutex);

     //解锁
    pthread_mutex_unlock(&a->mutex);

    return (a->balance);
}

account_test.c代码

#include "account.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

typedef struct{
    char name[20];   //名字
    Account *account;  //账户
    double amt;   //存取款金额
}OperArg;   //操作参数


//定义取款操作的线程运行函数
void*   withdraw_fn(void *arg)
{
    OperArg *oa = (OperArg*)arg;
    //取钱的账户和金额,取款失败返回0
    double amt = withdraw(oa->account, oa->amt);
    printf("%s(0x%lx) withdraw %f from account %d\n",
        oa->name, pthread_self(),
         amt, 
        oa->account->code);

    return (void*)0;
}

//定义存款操作的线程运行函数
void*   deposit_fn(void *arg)
{
    OperArg *oa = (OperArg*)arg;
    //存钱的账户和金额
    double amt = deposit(oa->account, oa->amt);
    printf("%s(0x%lx) withdraw %f from account %d\n",
        oa->name, pthread_self(),
         amt, 
        oa->account->code);

    return (void*)0;

}

//定义检查银行账户的线程运行函数
void*   check_fn(void *arg)
{
    OperArg* oa = (OperArg*)arg;

    double balance;
    balance = get_balance(oa->account);
    printf("balance %f", balance);

    return (void*)0;
}

int main(void)
{
    int err;
    pthread_t boy, girl;
    //第一个是账户编码号,第二个是余额
    //这里两个线程的账户都初始化为a
    Account *a = create_account(100001, 10000); 

    OperArg o1, o2;  //传入不同线程运行函数中
    strcpy(o1.name, "boy");
    o1.account = a;  
    o1.amt = 10000;


    strcpy(o2.name, "girl");
    o2.account = a;
    o2.amt = 10000;

    //启动两个子线程(boy 和girl线程)
    //同时去操作同一个银行账户
    if((err = pthread_create(&boy, NULL, withdraw_fn, (void*)&o1)) != 0)
    {
        perror("pthread create error");
    }
    if((err = pthread_create(&girl, NULL, withdraw_fn, (void*)&o2)) != 0)
    {
        perror("pthread create error");
    }
    pthread_join(boy, NULL);
    pthread_join(girl, NULL);

    //
    printf("account balance: %f\n", get_balance(a));
    destroy_account(a); //销毁账户


    return 0;
}

gcc运行编译结果

ji@ji-VM:~/c/pthread/account$ gcc account.c account_test.c 
ji@ji-VM:~/c/pthread/account$ ./a.out 
boy(0x7a8183200640) withdraw 10000.000000 from account 100001
girl(0x7a8182800640) withdraw 0.000000 from account 100001
account balance: 0.000000
ji@ji-VM:~/c/pthread/account$ 

4.互斥锁属性创建和销毁

互斥锁属性创建传入NULL则是创建标准互斥锁

5.设置和获取互斥锁进程共享属性

7.互斥锁类型操作

互斥锁初始化的时候

lockattr.c的代码,验证多次上锁同一互斥锁时,各种互斥锁属性对应的反应

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

int main(int argc,  char *argv[])
{
    //定义互斥锁
    pthread_mutex_t mutex;

    if(argc < 2){
        printf("-usage:%s [error|normal|recursive]\n",
            argv[0]);
        exit(1);
    }

    //定义互斥锁属性
    pthread_mutexattr_t mutexattr;
    //初始化互斥锁属性
    pthread_mutexattr_init(&mutexattr);

    //字符串比较函数strcmp(),字符串相等返回0
    if(!strcmp(argv[1], "error")){
        //设置互斥锁类型,为检错互斥锁
        pthread_mutexattr_settype(&mutexattr,
            PTHREAD_MUTEX_ERRORCHECK);
    }else if(!strcmp(argv[1], "normal")){
        //设置标准互斥锁
        pthread_mutexattr_settype(&mutexattr,
            PTHREAD_MUTEX_NORMAL);
    }else if(!strcmp(argv[1], "recursive")){
        //设置递归互斥锁
        pthread_mutexattr_settype(&mutexattr,
            PTHREAD_MUTEX_RECURSIVE);
    }

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

    //上锁
    if(pthread_mutex_lock(&mutex) != 0){
        printf("lock failure\n");
    }else{
        printf("lock success\n");
    }

    //上锁第二次,用于模拟第二次
    //上锁面对不同互斥锁属性
    if(pthread_mutex_lock(&mutex) != 0){
        printf("lock failure\n");
    }else{
        printf("lock success\n");
    }

    //释放锁
    pthread_mutex_unlock(&mutex);
    
    return 0;
}

运行结果,正常锁第二次调用会阻塞,

8.线程互斥——读写锁

1.线程使用互斥锁缺乏读并发性

2.读写锁创建和销毁

3.读写锁加锁和解锁

pthread_rwlock_rdlock()   //加读锁

pthread_rwlock_wrlock()//加写锁

rwlock.c上读锁,写锁多次案例

1.读和读不排斥;

2.写和写排斥;

3.读和写排斥;

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

//定义读写锁
pthread_rwlock_t rwlock;

int main(int argc, char *argv[])
{
    if(argc < 3){
        printf("-usage:%s [r|w] [r|w]\n", argv[0]);
        exit(1);
    }

    //读写锁初始化
    pthread_rwlock_init(&rwlock, NULL);

    if(!strcmp(argv[1], "r")){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) != 0){
            printf("first read lock failure\n");
        }else{
            printf("first read lock success\n");
        }
    }else if(!strcmp(argv[1], "w")){
        //加写锁
        if(pthread_rwlock_wrlock(&rwlock) != 0){
            printf("first write lock failure\n");
        }else{
            printf("first write lock success\n");
        }
    }

    if(!strcmp(argv[2], "r")){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) != 0){
            printf("second read lock failure\n");
        }else{
            printf("second read lock success\n");
        }
    }else if(!strcmp(argv[2], "w")){
        //加写锁
        if(pthread_rwlock_wrlock(&rwlock) != 0){
            printf("second write lock failure\n");
        }else{
            printf("second write lock success\n");
        }
    }

    //解锁,释放读写锁
    pthread_rwlock_unlock(&rwlock);
    pthread_rwlock_unlock(&rwlock);

    //摧毁读写锁
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

用读写锁解决银行取钱和存钱和查看余额之间的互斥利害

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

为微信小程序换皮肤之配置vant

微信小程序自带的控件虽然具有很好的通用性和简洁性&#xff0c;但在面对一些复杂的交互场景和个性化的设计需求时&#xff0c;可能会显得力不从心。其功能的相对基础使得开发者在实现诸如多步骤复杂表单提交、实时数据交互与可视化展示、高度定制化的界面布局等方面&#xff0…

K8S配置storage-class

简介 Kubernetes支持NFS存储&#xff0c;需要安装nfs-subdir-external-provisioner&#xff0c;它是一个存储资源自动调配器&#xff0c;它可将现有的NFS服务器通过持久卷声明来支持Kubernetes持久卷的动态分配。该组件是对Kubernetes NFS-Client Provisioner的扩展&#xff0…

html生成图片方案总结

动态图片生成是我们日常开发中经常遇到的需求&#xff0c;比如宣传海报生成&#xff0c;电商商品图动态生成等&#xff0c;本文总结出三种常见的 HTML 生成图片的方案。 一、html2canvas html2canvas库能够将 HTML 元素渲染为 Canvas&#xff0c;然后将其转换为图片。它的优点…

【力扣刷题实战】相同的树

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 力扣题目&#xff1a; 相同的树 题目描述 示例 1&#xff1a; 示例 2&#xff1a; 示例 3&#xff1a; 解题思路 题目理解 算法选择 具体思路 解题要点 完整代码&#xff08;C语言&#xff09; 兄弟们共勉 &#…

如何使用AdsPower指纹浏览器克服爬虫技术限制,安全高效进行爬虫!

随着中国开发者日益成熟&#xff0c;应用质量明显提升&#xff0c;越来越多的开发者选择出海寻找机会扩大市场。但“应用出海”说起来容易&#xff0c;做起来难。其中&#xff0c;最大的困恼就是对海外市场缺乏了解。 很多开发者会选择使用网络爬虫&#xff08;Web Crawling&a…

Python小游戏18——中国象棋

首先&#xff0c;你需要安装Pygame库。如果你还没有安装它&#xff0c;可以使用以下命令进行安装&#xff1a; bash pip install pygame 运行结果 代码如下&#xff1a; python import pygame import sys # 初始化Pygame pygame.init() # 屏幕尺寸 SCREEN_WIDTH 800 SCREEN_HE…

轴承寿命预测 (Python 预测模型全家桶)

往期精彩内容&#xff1a; Python-凯斯西储大学&#xff08;CWRU&#xff09;轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…

【IC验证_systemverilog】信号类型

IC验证_systemverilog 1.信号声明2.变量类型3.数据类型4.符号 1.信号声明 语法&#xff1a; 变量类型 信号类型 符号转换 位宽 信号名 深度&#xff1b;2.变量类型 &#xff08;1&#xff09;说明&#xff1a; systemverilog中的信号类型主要分为线网类型&#xff08;wire&a…

camera和lidar外参标定

雷达和相机的外参标定&#xff08;外部参数标定&#xff09;指的是确定两者之间的旋转和平移关系&#xff0c;使得它们的坐标系可以对齐。 文章目录 无目标标定livox_camera_calibdirect_visual_lidar_calibration 有目标标定velo2cam_calibration 无目标标定 livox_camera_ca…

照片不完整?来试试智能扩图,简直不要太满意!(不是广告)

生活中有些照片拍过之后&#xff0c;当时觉得很满意&#xff0c;但过段时间就恨当初没有拍一张完整的图片&#xff01; ——来自小白的感慨 当时跟家里的叮当一起去旅游&#xff0c;我给他拍了一张好看的照片&#xff1a; 今天这张照片如果是整图就好了&#xff01;好气哦&am…

在银河麒麟系统中Qt连接达梦数据库

解决在银河麒麟系统中使用Qt连接达梦数据库提示&#xff1a;project Error library odbc is not defined问题 一、编译ODBC 下载解压unixODBC&#xff08;http://www.unixodbc.org/unixODBC-2.3.1.tar.gz&#xff09; 打开终端&#xff0c;切换到unixODBC-2.3.1目录下&#x…

【WebDriver】浏览器驱动下载及其配置

一、Windows电脑环境搭建-Chrome浏览器 行业内&#xff0c;Chrome (谷歌) 浏览器对于自动化程序来讲是比较稳定的. 自动化程序推荐使用 Chrome 浏览器的原因有几个&#xff1a; 开发者工具&#xff1a;Chrome 提供强大的开发者工具&#xff0c;方便调试和测试自动化脚本。 稳…

时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解

时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解 目录 时序分解 | TTNRBO-VMD改进牛顿-拉夫逊算法优化变分模态分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 (创新独家)TTNRBO-VMD改进牛顿-拉夫逊优化算优化变分模态分解TTNRBO–VMD 优化VMD分解层数K和…

深度图和RGB图对齐

坐标系间的转换_坐标系转换-CSDN博客 深度图与彩色图的配准与对齐_彩色 深度 配准-CSDN博客 kinect 2.0 SDK学习笔记&#xff08;四&#xff09;--深度图与彩色图对齐_mapdepthframetocolorspace-CSDN博客 相机标定&#xff08;三&#xff09;-相机成像模型_相机小孔成像模型…

天润融通突破AI客服局限,三大关键提升文本机器人问答效果

近期&#xff0c;AI客服再次登上热搜&#xff0c;引发网友集体吐槽&#xff0c;比如AI客服虽然态度客气&#xff0c;但听不懂客户诉求&#xff0c;回答问题驴唇不对马嘴&#xff0c;解决不了问题...... 更有网友将这些问题升级到&#xff0c;企业就是不想解决问题才交给AI客服…

微服务之间调用,OpenFeign传递用户(RequestInterceptor接口)

场景&#xff1a;微服务之黑马商城项目-登录拦截器在网关完成用户的校验&#xff0c;并将用户信息&#xff08;用户id&#xff09;存入请求头&#xff0c;假设将购物车里面的商品进行结算就会生成订单并清空购物车&#xff0c;这里涉及到了交易服务模块远程调用购物车模块&…

Java避坑案例 - “激进”的线程池扩容策略及实现

文章目录 问题思路线程池的默认行为自定义线程池扩容策略Code实现小结 问题 Java 线程池是先用工作队列来存放来不及处理的任务&#xff0c;满了之后再扩容线程池。当我们的工作队列设置得很大时&#xff0c;最大线程数这个参数显得没有意义&#xff0c;因为队列很难满&#x…

OpenAI低调发布多智能体工具Swarm:让多个智能体协同工作!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

C++设计模式结构型模式———适配器模式

文章目录 一、引言二、适配器模式三、类适配器四、总结 一、引言 适配器模式是一种结构型设计模式&#xff0c;它在日常生活中有着广泛的应用&#xff0c;比如各种转换接头和电源适配器&#xff0c;它们的主要作用是解决接口不兼容的问题。就像使用电源适配器将220V的市电转换…

【Clickhouse】客户端连接工具配置

ClickHouse 是什么 ClickHouse 是一个分布式实时分析型列式存储数据库。具备高性能&#xff0c;支撑PB级数据&#xff0c;提供实时分析&#xff0c;稳定可扩展等特性。适用于数据仓库、BI报表、监控系统、互联网用户行为分析、广告投放业务以及工业、物联网等分析和时序应用场…