Linux Day14 :线程的创建与同步

news2024/12/24 21:10:17

一、简单认知

进程:一个正在运行的程序

线程:进程内部的一个执行路径

头文件:#include<pthread.h>

二、进程与线程的区别

进程是资源分配的最小单位,线程是 CPU 调度的最小单位
进程有自己的独立地址空间,线程共享进程中的地址空间
进程的创建消耗资源大,线程的创建相对较小
进程的切换开销大,线程的切换开销相对较小

三、线程的实现方式

用户级:开销小,可以创建很多,但不能利用多处理器资源。就算你弄了多了线程,但在内核中你只有一个线程,尽管你有多个处理器,还是通过时间片轮转法来实现并发

内核级:开销大(相对用户级来说),由内核直接管理,可以利用多处理器资源。Linux采用的就是这种

组合:介于这三种之间

在操作系统中,线程的实现有以下三种方式:

◼ 用户级线程 :用户级线程是完全在用户空间中实现的线程。操作系统内核对其一无所知,只知道进程的存在。用户级线程的创建、调度和管理完全由用户级的线程库完成。由于这些操作不需要内核的介入,所以用户级线程的创建和切换比内核级线程更加快速、高效。然而,由于操作系统对用户级线程一无所知,因此一个阻塞的用户级线程会导致整个进程阻塞,这是用户级线程的一个主要缺点。

◼ 内核级线程 :内核级线程是直接由操作系统内核支持和管理的线程。内核维护了所有内核线程的上下文信息,并负责线程的调度和切换。因此,内核级线程可以利用多处理器并行性,同时,当一个内核级线程阻塞时,内核可以调度该进程的其他线程执行。然而,内核级线程的创建和切换需要进行用户态到内核态的切换,因此成本比用户级线程高。

◼ 组合级线程:组合级线程是用户级线程和内核级线程的组合,试图结合两者的优点。在这种模型中,一个用户级线程对应于一个或多个内核级线程。这样,即使一个用户级线程阻塞,也不会阻塞整个进程,因为内核可以调度对应的其他内核级线程执行。同时,用户级线程的创建和切换可以在用户空间内完成,避免了频繁的用户态到内核态的切换。

Linux 实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux 把
所有的线程都当做进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来
表征线程。相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯
一隶属于自己的 task_struct,所以在内核中,它看起来就像是一个普通的进程(只是线程和
其他一些进程共享某些资源,如地址空间)。
使用ps -eLf以上图为例,进程id都是5620,但是有6个线程,其线程id从5620开始到5631( 所有的线程都当做进程来实现)

四、一些栗子

1、第一个小栗子

step1:不加睡眠函数

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void* fun(void* arg){
    for(int i=0;i<5;i++)
    {
        printf("fun run\n");
    }
}
int main()
{
    pthread_t  id;
    pthread_create(&id,NULL,fun,NULL);
    for(int i=0;i<5;i++)
    {
        printf("main run\n");
        //sleep(1);
    }
    exit(0);
}

结果:

一般是全是主函数,因为在调用线程函数的时候主函数已经执行完毕,Exit(0)了,所以不会打印fun函数

step 2:主函数加上睡眠函数

void* fun(void* arg){
    for(int i=0;i<5;i++)
    {
        printf("fun run\n");
    }
}
int main()
{
    pthread_t  id;
    pthread_create(&id,NULL,fun,NULL);
    for(int i=0;i<5;i++)
    {
        printf("main run\n");
        sleep(1);
    }
    exit(0);
}

2、第二个小栗子

循环打印所在位置

void*thread_fun(void*arg)
{
    int*p=(int*)arg;
    int index=*p;
    for(int i=0;i<3;i++)
    {
        printf("intdex=%d\n",index);
        sleep(1);
    }
}
int main()
{
    pthread_t id[5];
    for(int i=0;i<5;i++)
    {
        pthread_create(&id[i],NULL,thread_fun,(void*)&i);
    }
    for(int i=0;i<5;i++){
        pthread_join(&id[i],NULL);
    }
}

结果

问题:

这里将i的地址传给了fun()参数,解引用后就能得到i的值,这在单线程(一个内核)是没得问题的,但是多核多线程是有的,每个线程同时获取i的地址,但是线程启用是需要花费时间,等打印获取i的值时,那一刻的i不一定是你传入时期的i.

3.第三个小例子

将一个全局变量加到5000

#include<pthread.h>
int g_val=1;

void*fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        printf("val=%d\n",g_val++);
    }
}
int main()
{
    pthread_t id[5];
    int i=0;
    for(;i<5;i++)
    {
        pthread_create(&id[i],NULL,fun,NULL);
    }
     for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    exit(0);
}

结果不到5000,如果只有一个处理器的话不会出现两个程序并行的情况,但是处理器大于2时,出现两个程序并行。

解决方案:

1.加信号量

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<semaphore.h>
int g_val=1;
sem_t sem;
void*fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        sem_wait(&sem);
        printf("val=%d\n",g_val++);
        sem_post(&sem);
    }
}
int main()
{
    pthread_t id[5];
    sem_init(&sem,0,1);
    int i=0;
    for(;i<5;i++)
    {
        
        pthread_create(&id[i],NULL,fun,NULL);
        
    }
     for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    sem_destroy(&sem);
    exit(0);
}

2.加互斥锁

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<semaphore.h>
int g_val=1;
pthread_mutex_t mutex;
void*fun(void* arg)
{
    for(int i=0;i<1000;i++)
    {
        pthread_mutex_lock(&mutex);
        printf("val=%d\n",g_val++);
        pthread_mutex_unlock(&mutex);
    }
}
int main()
{
    pthread_t id[5];
    pthread_mutex_init(&mutex,NULL);
    int i=0;
    for(;i<5;i++)
    {
        
        pthread_create(&id[i],NULL,fun,NULL);
        
    }
     for(i=0;i<5;i++)
    {
        pthread_join(id[i],NULL);
    }
    pthread_mutex_destroy(&mutex);
    exit(0);
}

留一下一道思考题轮流打印abcabc按照这个顺序,该如何处理

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

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

相关文章

笔记(四)传统图机器学习的特征工程-连接

1、引言 工作&#xff1a;通过已知连接&#xff0c;补全未知连接 思想&#xff1a; 直接提取link特征&#xff0c;把link变成D维向量把link两端节点的D维向量拼接在一起&#xff08;不好&#xff0c;丢失了link本身的连接结构信息&#xff09; 2、连接分类 客观静态图&…

刻字机尖角补偿

1 刻字机尖角补偿原理 刀具切割直线段过渡方法在文章旋转偏心裁切刀切向跟踪及半径补偿 已经有过说明。刻字机由于刀具半径的影响&#xff0c;切割直角时会不直会比较圆滑&#xff0c;而且在闭合曲线的下刀点会容易不闭合。使用尖角补偿可以克服这些问题。 如上图所示&#xf…

大数据Flink(七十七):SQL窗口的Over Windows

文章目录 SQL窗口的Over Windows 一、​​​​​​​时间区间聚合

Say0l的安全开发-代理扫描工具-Sayo-proxyscan【红队工具】

写在前面 终于终于&#xff0c;安全开发也练习一年半了&#xff0c;有时间完善一下项目&#xff0c;写写中间踩过的坑。 安全开发的系列全部都会上传至github&#xff0c;欢迎使用和star。 工具链接地址 https://github.com/SAY0l/Sayo-proxyscan 工具简介 SOCKS4/SOCKS4…

网络安全中的欺骗攻击与防御技术

在Internet上计算机之间相互进行的交流建立在两个前提之下&#xff1a;认证、信任。 认证是网络上的计算机用于相互间进行识别的一种鉴别过程&#xff0c;经过认证的过程&#xff0c;获准相互交流的计算机之间就会建立起相互信任的关系。信任和认证具有逆反关系&#xff0c;即…

振弦传感器信号转换器在岩土工程监测中的注意事项

振弦传感器信号转换器在岩土工程监测中的注意事项 振弦传感器是岩土工程中常用的一种监测设备&#xff0c;用于监测土体和岩体的振动情况。而振弦传感器信号转换器则是将传感器所获得的振动信号转换为人类可读的数据&#xff0c;以方便监测人员进行数据分析和工程决策。 然而&a…

[php] 文件上传的一个项目emmm

项目完整地址 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>上传文件</title><link href"./css/bootstrap.min.css" rel"stylesheet"><style>font-face {fo…

亚马逊云科技创新加速周:以数智化手段加速中国企业出海之旅

近年来&#xff0c;越来越多的中国企业正在走向国际市场&#xff0c;中国企业如何在出海浪潮下稳重求进&#xff1f;9月18日-9月22日&#xff0c;新一期亚马逊云科技合作伙伴加速周将为您带来“智荟出海”专题。“智荟出海计划”是亚马逊云科技发布的一项合作计划&#xff0c;旨…

Golang 基础面试题 01

Golang 面试题合集.png 背景 在之前的文章中分享了 k8s 相关的面试题&#xff0c;本文我们重点来讨论和 k8s 密切相关的 Go 语言面试题。 这几年随着云原生的兴起&#xff0c;大部分后端开发者&#xff0c;特别是 Java 开发者都或多或少的想学习一些 Go 相关的技能&#xff0c;…

Postman使用_接口导入导出

文章目录 Postman导入数据Collections导出数据Environments导出数据Postman导出所有数据 Postman导入数据 可以导入collections&#xff08;接口集&#xff09;、Environments&#xff08;环境配置&#xff09;通过分享的链接或导出的JSON文件导入数据&#xff08;还可以从第三…

微信小程序——认识微信小程序

认识小程序 小程序与普通网页开发的区别 运行环境不同 网页运行在浏览器环境中&#xff0c;小程序运行在微信环境中API不同 由于运行环境不同&#xff0c;所以小程序中&#xff0c;无法调用DOM和BOM的API。但是&#xff0c;小程序中可以调用微信环境提供的各种API&#xff0c…

C++之生成详细汇编代码(二百一十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Python绘制柱状图之可视化神器Pyecharts

文章目录 安装Pyecharts绘制基本柱状图自定义柱状图调整柱状图颜色添加数据标签调整柱状图样式添加动画效果堆叠柱状图横向柱状图 更多类型的柱状图堆叠柱状图百分比堆叠柱状图极坐标柱状图 结论 &#x1f389;欢迎来到AIGC人工智能专栏~Python绘制柱状图之可视化神器Pyecharts…

让AI为您自动生成独特的商品标题,商品描述和营销文案

做外贸的朋友你知道吗&#xff1f;AI可为您自动生成独特的商品标题&#xff0c;商品描述和营销文案 AI生成的商品标题是一项强大的工具&#xff0c;尤其在外贸和跨境电商行业中&#xff0c;它可以帮助您轻松创造引人注目的标题&#xff0c;吸引潜在客户。以下是一个针对外贸和…

JDK 动态代理

动态代理机制 Java 里面&#xff0c;动态代理是通过 Proxy.newProxyInstance()方法来实现的&#xff0c;它需要传入被动态代理的接口类 // 生成代理文件写入磁盘 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");ITrad…

DP专题5 不同路径||

题目&#xff1a; 思路&#xff1a; 这道题&#xff0c;思路跟 不同路径| 思路一样&#xff0c;只是不同的是&#xff0c;有障碍物这一块&#xff0c;我们的二维dp数组初始化的时候&#xff0c;要注意&#xff0c;机器人只能向右和向下&#xff0c;所以初始化第一行和第一列的…

黑龙江省DCMM认证、CSMM认证、CMMM认证、知识产权等政策奖励

2023年8月28日 为深入落实党的二十大精神&#xff0c;认真落实省第十三次党代会关于创新龙江建设的部署要求&#xff0c;全面贯彻新发展理念&#xff0c;融入和服务构建新发展格局&#xff0c;实施创新驱动发展战略&#xff0c;着力建设创新龙江&#xff0c;不断塑造振兴发展新…

基于Yolov8网络进行目标检测(二)-安装和自定义数据集

关于Yolov8的安装在前一个环节忽略了&#xff0c;其实非常简单&#xff0c;只需要以下两个步骤&#xff1a; 1、安装pytorch pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 2、安装ultralytics pip install ultralytics 为什…

功率放大器驱动压电陶瓷有哪些应用

功率放大器在压电陶瓷材料领域的应用。首先&#xff0c;介绍了压电陶瓷的基本概念和特性。然后&#xff0c;阐述了功率放大器的基本原理和分类。接着&#xff0c;分析了功率放大器在压电陶瓷材料领域的应用&#xff0c;包括声波发生器、超声波清洗器、超声波切割器、医疗超声波…

企业架构LNMP学习笔记44

小工具&#xff1a; memcached_tool.php软件&#xff0c;可以查看memcached运行状态、key&#xff08;item&#xff09;的数量、内存使用量等。 1&#xff09;上传memcached_tool.php到web服务器上&#xff1a; 上传到虚拟机主机可以访问的目录即可。需要php的运行环境&…