十五、Linux线程(二)

4.线程的分离属性

通过属性设置线程的分离

1.线程属性类型: pthread_attr_t attr;

2.线程属性操作函数:

        (1)对线程属性变量的初始化

                int pthread_attr_init(pthread_attr_t* attr);

        (2)设置线程分离属性

                int pthread_attr_setdetachstate(

                        pthread_attr_t* attr;

                        int detachstate;

                 );

参数:

        attr : 线程属性

        detachstate:

                PTHREAD_CREATE_DETACHED(分离)

                PTHREAD_CREATE_JOINABLE(非分离)

        (3)释放线程资源函数

                int pthread_attr_destroy(pthread_attr_t* attr);

5.线程同步

demo:

两个线程强占交替进行

数据混乱:

1.操作了共享资源

2.CPU调度问题

解决:

        线程同步:什么是同步?,协同步调,按照先后顺序操作执行

线程同步的思想:

6.互斥锁(互斥量)

特点:多个线程访问共享数据的时候是串行的

缺点:效率低

1.互斥锁使用的步骤

创建互斥锁: pthread_mutex_t mutex;

初始化:pthread_mutex_init(&mutex,NULL); ——mutex = 1

找到线程共同操作的共享数据:

        操作共享资源之前加锁:

        pthread_mutex_lock(&mutex); //阻塞 ——mutex = 0

        pthread_mutex_trylock(&mutex); // 如果锁上锁直接返回,不阻塞

        共享数据操作//临界区 ,越小越好

        解锁:pthread_mutex_unlock(&mutex); // ——mutex = 1

                阻塞在锁上的线程会被唤醒

销毁:pthread_mutex_destroy(&mutex)

2.互斥锁相关函数

初始化互斥锁:

pthread_mutex_init(

pthread_mutex_t* restrict mutex,

const pthread_mutexattr_t* restrict attr,

);

加锁:

pthread_mutex_lock(pthread_mutex* mutex)

mutex:

        没被锁上:当前线程会将这把锁锁上

        被锁上了:当前线程阻塞,锁被打开之后,线程解除阻塞

尝试加锁,失败返回,不阻塞:

pthread_mutex_trylock(pthread_mutex_t* mutex);

        没有锁上:当前线程会被这把锁加锁

        被锁上了:不会阻塞,返回

        返回0:加锁 成功   没锁上:返回错误号

if( pthread_mutex_trylock(& mutex)==0)

{

        //尝试加锁,并且成功了

        //访问共享资源

}

else

{

        //错误处理

        //或者等待,再次尝试加锁

}

解锁:

pthread_mutex_unlock(pthread_mutex_t* mutex)

销毁互斥锁:

pthread_mutex_destroy(pthread_mutex_t* mutex );

如果我们想要使用互斥锁同步线程所以线程都需要加锁

7.原子操作

CPU处理一个指令,进程/线程在处理完这个指令之前是不会失去CPU的

所谓原子操作,也就是一个独立而不可分割的操作,就像原子被认为是不可分割颗粒一样

更广泛的意义下原子操作是指一系列必须整体完成的操作步骤,如果任何一步操作没有完成,那么所有完成的步骤都必须回滚,这样就可以保证要么所有操作步骤都未完成,要么所有操作步骤都被完成

//示例代码1

void* procucer(void * arg)

{

        while(1)

        {

                //创建一个链表的节点

                Node * newNode = (Node*)malloc(sizeof(Node));

                //init

                newNode‐>data = rang()%100;

                newNode ‐>next = head;

                head = newNode;

                printf("+++product:%d\n",newNode‐>data);

                sleep(rang()%3);

        }

        reutn NULL;

}

//示例代码2

void* procucer(void * arg)

{

        while(1)

        {

                //创建一个链表的节点

                Node * newNode = (Node*)malloc(sizeof(Node));

                //init

                newNode‐>data = rang()%100;

                //模拟原子操作:

                pthread_mutex_lock(&mutex);

                newNode ‐>next = head;

                head = newNode;

                printf("+++product:%d\n",newNode‐>data);

                pthread_mutex_unlock(&mutex);

                sleep(rang()%3);

        }

        reutn NULL;

}

8.死锁

造成死锁的原因:

1.自己锁自己

for(int i = 0;i<MAX;i++)

{

        pthread_mutex_lock(&mutex);

        pthread_mutex_lock(&mutex);

        int crt = number;

        crt++;

        number = crt;

        printf("thread A id = %ld,number = %d\n",pthread_self(),number);

        pthread_mutex_unlock(&mutex);

        usleep(10);

}

2.

线程1:对共享资源A加锁成功-A

线程2:对共享资源B加锁成功-B

线程1访问共享资源B,对B锁加锁-线程1阻塞在B锁上

线程2访问共享资源A,对A锁加锁-线程2阻塞在A锁上

如何解决:

--让线程按照一定的顺序去访问共享资源

--在访问其他锁的时候,需要先将自己的锁解开

--try_lock

9.读写锁

1.读写锁是几把锁?

一把锁

pthread_rwlock_t lock;

2.读写锁的类型

读锁-对内存做读操作

写锁-对内存做写操作

3.读写锁的特性

线程A锁成功,又来了三个线程,做操作,可以加锁成功

        读共享——并行处理

线程A锁成功,又来了三个线程,做操作,三个线程阻塞

        写独占——串行处理

线程A锁成功,又来了三个线程,做操作,三个线程阻塞

        写独占——写完再读

线程A锁成功,又来了三个线程,做操作,三个线程阻塞

        读独占——读完再写

线程A加读锁成功,又来了B线程加写锁阻塞,又来了C线程加读锁阻塞

        读写不可以同时进行

        写的优先级高

4.读写锁场景练习

1、线程A持有写锁,线程B请求读锁 :线程B阻塞

2、线程A持有读锁,线程B请求写锁 :线程B阻塞

3、线程A持有读锁,线程B请求读锁 :线程B加锁

4、线程A持有读锁,线程B请求写锁,线程C请求读锁 :

        1.线程A持有读锁,线程B阻塞,线程C阻塞

        2.线程A读完之后,线程B加锁,线程C阻塞

        3.线程B写完之后,线程C加锁

5、线程A持有写锁,线程B请求读锁,线程C请求写锁:

        1.线程A持有写锁,线程B阻塞,线程C阻塞

        2.线程A写完之后,线程C加锁, 线程B阻塞

        3.线程C写完之后,线程B加锁

5.读写锁的适用场景

互斥锁:

        读写串行

读写锁:

        读:并行

        写:串行

6.主要操作函数

初始化读写锁:

        pthread_rwlock_init(pthread_rwlock_t* restrict rwlock,

        const pthread_rwlockattr_t* restrict attr );

加读锁:

        pthread_rwlock_rdlock(pthread_rwlock_t* rdlock);

                阻塞:之前对这把锁加的是写锁的操作

尝试加读锁:

        pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);

                加锁成功:返回0

                失败:返回错误号

加写锁:

        pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);

                阻塞:上一次加写锁还没解锁

                阻塞:上一次加读锁还没解锁

尝试加写锁:

        pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);

                加锁成功:返回0

                失败:返回错误号

解锁:

        pthread_rwlock_unlock(pthread_rwlock_t* rwlock);

销毁读写锁:

        pthread_rwlock_destroy(pthread_rwlock_t* rwlock);

7.练习

三个线程不定时写同一全局变量,五个线程不定时期读同一全局资源

先不加锁:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int num = 0;void* write_fun(void* arg)
{while(1){num++;printf("write : %ld,%d\n",pthread_self(),num);usleep(500);}
}
void* read_fun(void* arg)
{while(1){printf("read : %ld,%d\n",pthread_self(),num);usleep(500);}
}int main()
{pthread_t p[8];for(int i = 0;i < 3;i++){pthread_create(&p[i],NULL,write_fun,NULL);}for(int i = 3;i < 8;i++){pthread_create(&p[i],NULL,read_fun,NULL);}for(int i = 0;i < 8;i++){pthread_join(p[i],NULL);}return 0;
}

在读的时候会发生混乱

加锁之后:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>int num = 0;
//create rwlock
pthread_rwlock_t lock;void* write_fun(void* arg)
{while(1){//lockpthread_rwlock_wrlock(&lock);num++;printf("write : %ld,%d\n",pthread_self(),num);//unlockpthread_rwlock_unlock(&lock);usleep(500);}
}
void* read_fun(void* arg)
{while(1){//lockpthread_rwlock_rdlock(&lock);printf("read : %ld,%d\n",pthread_self(),num);//unlockpthread_rwlock_unlock(&lock);usleep(500);}
}int main()
{//init rwlockpthread_rwlock_init(&lock,NULL);pthread_t p[8];for(int i = 0;i < 3;i++){pthread_create(&p[i],NULL,write_fun,NULL);}for(int i = 3;i < 8;i++){pthread_create(&p[i],NULL,read_fun,NULL);}for(int i = 0;i < 8;i++){pthread_join(p[i],NULL);}//destroy rwlockpthread_rwlock_destroy(&lock);return 0;
}

这次在读的时候不混乱了

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

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

相关文章

stm32 ADC实例解析(3)-多通道采集互相干扰的问题

文章目录 一、问题现象&#xff1a;二、原因分析&#xff1a;1、测量值不准问题分析&#xff1a;2、采样干扰问题分析 三、解决办法&#xff1a;1、硬件&#xff1a;&#xff08;1&#xff09;、电源供电&#xff08;2&#xff09;、引脚电容&#xff08;3&#xff09;、减少采…

定制ShardingSphere-Proxy镜像满足业务需求

Sharding官方提供的proxy镜像是基础版的&#xff0c;如果我们使用Sharding有以下任意需求&#xff0c;就需要添加额外的依赖到容器{path}/ext-lib目录下。 向Docker容器中添加jar包的方式多种多样&#xff0c;推荐采取使用Dockerfile的方式添加依赖。将原有的镜像作为基础镜像&…

【数据分享】1901-2023年我国省市县镇四级的逐年降水数据(免费获取/Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月降水栅格数据和Shp和Excel格式的省市县四级逐月降水数据&#xff0c;原始的逐月降水栅格数据来源于彭守璋学者在国家青藏高原科学数据中心平台上分享的数据&#xff01;基于逐月数据我们采用求年累计值的方法得到逐年降水栅格数据&#…

virtualBox部署minikube+istio

环境准备 virtualBox安装 直接官网下载后安装即可&#xff0c;网上也有详细教程。镜像使用的centos7。 链接&#xff08;不保证还可用&#xff09;&#xff1a;http://big.dxiazaicc.com/bigfile/100/virtualbox_v6.1.26_downcc.com.zip?auth_key1730185635-pWBtV8LynsxPD0-0-…

深入浅出WebSocket(实践聊天室demo)

文章目录 什么是WebSocket?WebSocket连接过程WebSocket与Http的区别重连机制完整代码使用方法心跳机制实现聊天室demo(基于Socket.io)参考文章、视频小广告~什么是WebSocket? WebSocket 是一种在单个TCP连接上进行全双工通信的协议(计算机网络应用层的协议) 在 WebSocket A…

[CKS] Audit Log Policy

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于audit policy的题目。 What’s the audit policy 使用K8s Audit Policy&#xff0c;管理员可以定义哪些操作需要被审计&#xff0c;包括创建、删除、更新和查看集群中的资源。审计记录包括操作的时…

【C++】map和set的介绍及使用

前言&#xff1a; map和 set 是 C STL&#xff08;标准模板库&#xff09;中的两种非常重要的容器&#xff0c;它们基于一种叫做平衡二叉搜索树&#xff08;通常是红黑树&#xff09;的数据结构来实现。在 C 中&#xff0c;map 是一个键值对容器&#xff0c;set 只存储唯一的键…

ai外呼机器人的作用有哪些?

ai外呼机器人具有极高的工作效率。日拨打成千上万通不是问题&#xff0c;同时&#xff0c;机器人还可以快速筛选潜在客户&#xff0c;将更多精力集中在有价值的客户身上&#xff0c;进一步提升营销效果。183-3601-7550 ai外呼机器人的作用&#xff1a; 1、搭建系统&#xff0c…

QT版发送邮件程序

简单的TCP邮箱程序 **教学与实践目的&#xff1a;**学会网络邮件发送的程序设计技术。 1.SMTP协议 邮件传输协议包括 SMTP&#xff08;简单邮件传输协议&#xff0c;RFC821&#xff09;及其扩充协议 MIME&#xff1b; 邮件接收协议包括 POP3 和功能更强大的 IMAP 协议。 服务…

汽车牌照识别系统的设计与仿真(论文+源码)

1设计原理 车牌识别系统的设计是一项利用车辆的动态视频或者静态图像实现牌照区域定位车牌号码识别的技术。其硬件部分通常包括触发设备、拍摄设备、照明设备、图像收集设备、进行车牌号码识别的处理器等&#xff0c;其软件的关键部分包含车牌区域定位的算法、车牌字符的分割算…

vue通过iframe方式嵌套grafana图表

文章目录 前言一、iframe方式实现xxx.xxx.com拒绝连接登录不跳转Cookie 的SameSite问题解决不显示额外区域(kiosk1) 前言 我们的前端是vue实现的&#xff0c;监控图表是在grafana中的&#xff0c;需要在项目web页面直接显示grafana图表 一、iframe方式实现 xxx.xxx.com拒绝连…

学习笔记:黑马程序员JavaWeb开发教程(2024.11.9)

9.1 Mybatis-基础操作-环境准备 这里也没做&#xff0c;到时候写案例&#xff0c;如果需要环境配置什么的&#xff0c;可以看看这个 9.2 Mybatis-基础操作-删除 删除需要动态获取需要删除的id&#xff0c;使用方法传参&#xff0c;#{}的方式实现 在编写的delete方法中&a…

[Docker#3] LXC | 详解安装docker | docker的架构与生态

目录 1.LXC容器操作 安装LXC LXC容器操作步骤 2.理论 LXC 是什么&#xff1f; Docker 是什么 Docker 和虚拟机的区别 Docker 和 JVM 虚拟化的区别 Docker 版本 ⭕Docker 官方网站&#xff08;建议收藏&#xff09; Docker 架构 生活案例 Docker 生态 Docker 解决…

Spark的学习-02

Spark Standalone集群的安装 架构&#xff1a;普通分布式主从架构 主&#xff1a;Master&#xff1a;管理节点&#xff1a;管理从节点、接客、资源管理和任务 调度&#xff0c;等同于YARN中的ResourceManager 从&#xff1a;Worker&#xff1a;计算节点&#xff1a;负责利用自己…

白杨SEO:百度在降低个人备案类网站搜索关键词排名和流量?怎样应对?【参考】

很久没有写百度或者网站这块内容了&#xff0c;一是因为做百度网站朋友越来越少&#xff0c;不管是个人还是企业&#xff1b;二是百度上用户搜索与百度给到网站的流量都越来越少。 为什么想到今天又来写这个呢&#xff1f;因为上个月有个朋友来咨询我说网站百度排名全没了&…

一个怀旧,俺的第一个共享软件

今天网友说起了 福彩双色球的程序。俺就想起这个来了&#xff0c;这是俺的第一个共享软件&#xff0c;收入大约15000。在当时来说&#xff0c;速度算是最快的。有些地方用了汇编优化&#xff08;题外话&#xff0c;最近俺看到新闻&#xff0c;FFmpeg的作者也用汇编优化 性能提升…

QCustomPlot添加自定义的图例,实现隐藏、删除功能(二)

文章目录 QCustomPlot初识和基本效果图实现步骤:详细代码示例:实现原理和解释:使用方法:其他参考要实现一个支持复选框来控制曲线显示和隐藏的自定义 QCPLegend 类,可以通过继承 QCPLegend 并重写绘制和事件处理方法来实现,同时发出信号通知曲线的状态变更。 QCustomPl…

96.【C语言】存储体系结构

目录 1.金字塔图 2.形象理解的图 3.分析 4.推荐阅读 1.金字塔图 2.形象理解的图 3.分析 缓存的大小<<内存的大小 缓存分三级:速度:一级>二级>三级 在95.【C语言】数据结构之双向链表的头插,头删,查找,中间插入,中间删除和销毁函数文章遗留了一个问题,缓存命…

智能合约在供应链金融中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 智能合约在供应链金融中的应用 引言 智能合约概述 定义与原理 发展…

ODOO学习笔记(4):Odoo与SAP的主要区别是什么?

Odoo 和 SAP 都是知名的企业资源规划&#xff08;ERP&#xff09;软件&#xff0c;它们之间存在以下一些主要区别&#xff1a; Odoo与SAP的区别 一、功能特点 功能广度 Odoo&#xff1a;提供了一整套全面的业务应用程序&#xff0c;涵盖了销售、采购、库存管理、生产、会计、…