linux17 线程安全 线程同步

news2024/11/23 15:27:47

1、线程安全:

多线程程序无论调度顺序如何,都能保证程序 的正确性,就说该程序处于线程安全的状态

1)、同步

2)、线程安全函数//有的函数不适合多线程使用,是函数自身的原因。

2、线程安全函数

1)非线程安全函数

分割函数//不是线程安全函数

strtok(buff,"  分隔符")//非线程安全函数,

如果有静态变量或者全局变量,对于多线程来说,访问是不安全的。属于非线程安全函数

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

void *fun(void*arg)
{
char buff[128]={a b c d };
char*s=strtok(buff," ");
while(s!=NULL)
{
printf("%s\n",s);
s=strtok(NULL," ");
}

}

int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
char arr[128]={1 2 3 4 5};
char*p=strtok(arr," ");
whlie(p!=NULL)
{
printf("%s\n",p);
p=strtok(NULL," ");
}
pthread_join(id,NULL);
exit(0);
}

2)线程安全函数 

线程安全分割函数

strtok_r(buff," ",&ptr);

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

void *fun(void*arg)
{
char buff[128]={a b c d };
char*ptr=NULL;
char*s=strtok_r(buff," ",&ptr);
while(s!=NULL)
{
printf("%s\n",s);
s=strtok_r(NULL," ",&ptr);
}

}

int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
char arr[128]={1 2 3 4 5};
char*ptr=NULL;
char*p=strtok_r(arr," ",&ptr);
whlie(p!=NULL)
{
printf("%s\n",p);
p=strtok_r(NULL," ",&ptr);
}
pthread_join(id,NULL);
exit(0);
}

3、多线程程序执行fork()

1)多线程程序:

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

void*fun(void *arg)
{
for(int i=0;i<5;i++)
{
printf("fun(%d) run\n",getpid());
sleep(1);
}

}

int main()
{

pthread_t id;
pthread_create(&id,NULL,fun,NULL);


for(int i=0;i<5;i++)
{
printf("main(%d) run\n",getpid());
sleep(1);
}

pthread_join(id,NULL);
exit(0);
}

2)多线程 复制子进程

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

void*fun(void *arg)
{
for(int i=0;i<5;i++)
{
printf("fun(%d) run\n",getpid());
sleep(1);
}

}

int main()
{

pthread_t id;
pthread_create(&id,NULL,fun,NULL);

fork ();

for(int i=0;i<5;i++)
{
printf("main(%d) run\n",getpid());
sleep(1);
}

pthread_join(id,NULL);
exit(0);
}

多线程 fork()后只会执行一条路径,他在哪一个路径中他就会执行那一条路径,但是其他路径的资源他是有的,只不过不执行了

4、创建一个锁,fork()之后看子进程的情况

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/wait.h>

pthread_mutex_t mutex;
void*fun(void *arg)
{

pthread_mutex_lock(&mutex);
sleep(5);//线程睡眠5秒
pthread_mutex_unlock(&mutex);
printf(" fun free\n");
}

int main()
{

pthread_t id;
pthread_mutex_init(&mutex,NULL);
pthread_create(&id,NULL,fun,NULL);

sleep(1);//主线程睡眠一秒

pid_t pid=fork();//复制的时候,父进程处于加锁状态
if(pid==0)
{
printf("child lock\n");
pthread_mutex_lock(&mutex);
printf("child success");
pthread_mutex_unlock(&mutex);
}
else
{
wait(NULL);
}

printf("main over");

pthread_mutex_destroy(&mutex);
pthread_join(id,NULL);
exit(0);

}

子进程没有加锁成功 

1)加锁失败原因:

 父进程和子进程的锁各自是各自的,是两把锁。

锁的状态,会在复制进程时,被复制,在复制时,父进程的锁是加锁,复制后,子进程的锁也是加锁,同样不加锁也是。是不固定的,子进程中锁的状态不清晰。

2)解决办法:pthread_atfork()

会在没有人用锁的情况下对进程进行复制,确保子进程所得状态时清晰的。

void parent_fun(void)
{
pthread_mutex_lock(&mutex);
}
void child_fun(void)
{
pthread_mutex_unlock(&mutex);
}


int main()
{
pthread_atfork(parent_fun,child_fun.child_fun);
//写入主函数,会在复制子程序之前执行
}

弊端是会延迟fork的复制

5、进程同步——条件变量

进程同步的方法:信号量  互斥锁   读写锁   条件变量

线程先将自己堵塞在条件变量等待队列上,等条件满足之后,唤醒一个或者全部

//条件满足就工作,条件不满足就休息//条件由用户决定。

在唤醒的时候,不希望有别的进出这个给队列,所以在唤醒时加锁

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

pthread_mutex_t mutex;
pthread_cond_t cond;

char buff[128]={0};

void *funa(void*arg)
{
while(1)
{
    pthread_mutex_lock(&mutex);//唤醒前加锁
    pthread_cond_wait(&cond,&mutex);
    pthread_mutex_unlock(&mutex);

    if(strncmp(buff,"end",3)==0)
    {
        printf("funa:%s",buff);


    }




}

}
void*funb(void*arg)
{
{
    while (1)
    {
    pthread_mutex_lock(&mutex);
    pthread_cond_wait(&cond,&mutex);
    pthread_mutex_unlock(&mutex);
    }
        if(strncmp(buff,"end",3)==0)
    {
        printf("funb:%s",buff);


    }
    
}
}



int main()
{

pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_t id1,id2;
pthread_create(&id1,NULL,funa,NULL);
pthread_create(&id2,NULL,funb,NULL);

while(1)
{
    char tmp[128]={0};
    fgets(tmp,128,stdin);

    strcpy(buff,tmp);
    if(strncmp(tmp,"end",3)==0)
    {

        pthread_cond_broadcast(&cond);//唤醒全部进程
        break;
    }
    else
    {
        pthread_cond_signal(&cond);//唤醒单个进程(轮流唤醒)

    }
}

pthread_join(id1,NULL);
pthread_join(id2,NULL);
}

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

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

相关文章

java-垃圾回收与算法

垃圾回收与算法 1. 如何确定垃圾 1. 引用计数法 在 Java 中&#xff0c;引用和对象是有关联的。如果要操作对象则必须用引用进行。因此&#xff0c;很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。简单说&#xff0c;即一个对象如果没有任何与之关联的引用&…

【Freertos基础入门】任务调度

文章目录 前言对于前面博客的总结一、任务调度算法是什么&#xff1f;1.调度算法是什么以及freertos的调度算法2.抢占式优先级调度3.时间片轮转调度 二、配置调度算法总结 前言 本系列基于stm32系列单片机来使用freerots 任务管理是实时操作系统&#xff08;RTOS&#xff09;…

VS2015+mysql5.7升级到VS2019+mysql-8.0.34

本来一开始是安装的vs2022社区版&#xff0c;结果没找到mysql-for-visualstudio对应的2022的版本。 原来&#xff1a;VS2015mysql5.7 安装的插件&#xff1a; mysql-for-visualstudio-2.0.5.msi mysql-connector-net-6.10.8.msi 升级后&#xff1a;VS2019mysql-8.0.34 安…

深入理解linux内核--块设备驱动程序

块设备的处理 块设备驱动程序上的每个操作都涉及很多内核组件&#xff1b;其中最重要的一些如图14-1所示。 例如&#xff0c;我们假设一个进程在某个磁盘文件上发出一个read()系统调用 ——我们将会看到处理write请求本质上采用同样的方式。 下面是内核对进程请求给予回应的一…

FPGA芯片IO口上下拉电阻的使用

FPGA芯片IO口上下拉电阻的使用 为什么要设置上下拉电阻一、如何设置下拉电阻二、如何设置上拉电阻为什么要设置上下拉电阻 这里以高云FPGA的GW1N-UV2QN48C6/I5来举例,这个芯片的上电默认初始化阶段,引脚是弱上来模式,且模式固定不能通过软件的配置来改变。如下图所示: 上…

Openwrt指定延迟脚本

在某些情况下&#xff0c;我们需要对指定网络接口指定延迟&#xff0c;以达到我们想要实验的效果延迟。 脚本如下&#xff1a; #!/bin/bash # #初始化 tc qdisc del dev br-lan root echo "1. 添加延迟规则 2. 删除延迟规则" read -p "请选择操作&#xff1a;&q…

素数线性筛法 → 欧拉筛

【题目来源】https://www.acwing.com/problem/content/870/【题目描述】 给定一个正整数 n&#xff0c;请你求出 1∼n 中质数的个数。【输入格式】 共一行&#xff0c;包含整数 n。【输出格式】 共一行&#xff0c;包含一个整数&#xff0c;表示 1∼n 中质数的个数。【数据范围…

【数字实验室】时钟切换

大部分开发者使用 BUFGCTRL 或 BUFGMUX进行时钟切换&#xff0c;它们在时钟切换上可以提供无毛刺输出。然而&#xff0c;了解所涉及的原理是有好处的。 当然&#xff0c;无论我们在同步逻辑中使用哪种技术&#xff0c;重要的是要确保在进行时钟切换时输出上没有毛刺。任何故障都…

无涯教程-Perl - times函数

描述 此函数返回一个四元素列表,为当前进程及其子进程提供用户,系统,子进程和子系统时间。 语法 以下是此函数的简单语法- times返回值 此函数返回ARRAY,($usertime,$systemtime,$childsystem,$childuser) 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl -w($use…

一、ls 标准输出时出现乱码符号及解决办法

问题描述&#xff1a;采用 QSSh 登录远程主机时&#xff0c;执行 ls 指令&#xff0c;标准输出中出现乱码符号 如下&#xff0c;在成功 SSH 到远程主机后&#xff0c;执行 ls 指令&#xff0c;标准输出中出现一堆不认识的符号。 从标准输出来看&#xff0c;英文和中文并没有乱…

安科瑞无线测温产品在浙江某半导体项目的应用-安科瑞黄安南

摘 要&#xff1a;半导体被誉为“制造业的大脑”&#xff0c;在关系国家安全和国民经济命脉的主要行业和关键领域占据支配地位&#xff0c;是国民经济的重要支柱。随着数字技术的发展和数字经济在国民经济中所占比重越来越高&#xff0c;半导体产业的重要性还会进一步提升。安全…

文心一言 VS 讯飞星火 VS chatgpt (77)-- 算法导论7.3 2题

二、如果用go语言&#xff0c;在 RANDOMIZED-QUICKSORT 的运行过程中&#xff0c;在最坏情况下&#xff0c;随机数生成器 RANDOM 被调用了多少次?在最好情况下呢?以θ符号的形式给出你的答案? 文心一言&#xff1a; 在 RANDOMIZED-QUICKSORT 的运行过程中&#xff0c;最坏…

使用贝塞尔曲线算法制作曲线

一阶贝塞尔曲线 使用两个点绘制线段 p3p1(p2-p1)*t p1:起点;p2:终点;t:0-1;p3:线段L12上的点 两个点和t的变化(0-1)可得到一条线段 二阶贝塞尔曲线 使用三个点绘制曲线 p12p1(p2-p1)*t p23p2(p3-p2)*t p123p12(p23-p12)*t p12是线段L12上的点&#xff0c; p23是线段L23上的…

android:绘图 (android.graphics包)

android:绘图 View&#xff1a;组件&#xff0c;理解为画布 Drawable:所有可见对象的描述&#xff0c;理解为&#xff1a;素材类 Bitmap&#xff1a;图片类 Canvas&#xff1a;画笔 Paint&#xff1a;画笔样式与颜色、特效的集合 近期很多网友对Android用户界面的设计表示很感…

Lnton羚通关于如何解决nanoPC-T4 upgrade报错问题?

nanoPC-T4 在 ​​# sudo apt update 和 sudo apt upgrade​​升级或安装软件 ​​sudo apt install xxx​​时遇到以下问题&#xff1a;​​Failed to set up interface with /etc/hostapd/​ Setting up hostapd (2:2.6-15ubuntu2.8) ... Job for hostapd.service failed be…

学习 Linux 系统路线图

在计算机科学领域&#xff0c;Linux 操作系统以其稳定性、灵活性和卓越性能而受到广泛欢迎。要真正掌握 Linux 系统&#xff0c;我们需要深入了解其关键组成部分&#xff0c;包括系统、内存、进程、网络和存储等模块。让我们深入探索这些模块&#xff0c;以建立起对 Linux 系统…

【轻量级神经网络】ShuffleNetv1-2详解

文章目录 1、ShuffleNetV11.1、分组卷积1.2、channel shuffle1.3、ShuffleNet基本单元1.4、整体结构 2、ShuffleNetV22.1、基本单元2.2、整体结构 1、ShuffleNetV1 1.1、分组卷积 Group convolution是将输入层的不同特征图进行分组&#xff0c;然后采用不同的卷积核再对各个组…

KVM配置使用ovs网桥

KVM配置使用ovs网桥 1、安装openvswitch 2、启动服务 3、配置ovs 重启网络服务 systemctl restart network 4、 KVM配置使用ovs网桥 配置生效&#xff1a;virsh net-define br0.xml virsh net-start bro virsh net-autostart br0 5、虚…

怎么实现技术评卷时间0投入的?(上)

01 痛苦的技术问答题评审 指针走到了九点&#xff0c;凝视着时钟的技术招聘官Jasmine从昏沉中回到现实&#xff0c;她将咖啡连同叹息一口抿了下去&#xff0c;并端正坐在电脑前。又是一天的评卷日…… 技术招聘已持续数周&#xff0c;公司筛选出了100位嵌入式工程师候选人的技…

ATA-2000系列高压放大器——应用场景介绍

ATA-2000系列高压放大器——应用场景介绍 ATA-2000系列是一款理想的可放大交、直流信号的高压放大器。最大差分输出1600Vp-p (800Vp)高压&#xff0c;可以驱动高压型负载。电压增益数控可调&#xff0c;一键保存常用设置&#xff0c;为您提供了方便简洁的操作选择&#xff0c;同…