C语言线程

news2024/12/22 22:26:37

线程

多个进程中通过轮流使用CPU来完成自己的任务,如果多个进程的操作都一模一样那么CPU的开销就会很大,因为进程的地址都是私有的,如果CPU对相同的操作只执行一次,后面再遇到直接去获取即可,这样大大降低了CPU的开销,如此就引出了线程。

 所谓线程就是一个轻量级的进程。
在同一进程中可以创建多个线程共享这个进程的地址空间。
线程使操作系统可调度的最小单位。

对于操作系统而言,线程与进程没有区别。

线程的基本操作

  1. 创建线程

     2.删除线程

     3.控制线程

线程相关函数

  1. pthread_join(pthread_t tid, void ** retval) : 等待子线程结束后回收资源。

    1. 参数1:线程号。
    2. 参数2:线程函数的返回结果。

pthread_exit(void*); 线程函数中的返回函数,跟return类似。 

  1. pthread_detach(pthread_t id); // 主线程中调用线程分离,子线程中调用将子线程设置为游离态,主线程不再阻塞式等待子线程完成后才进行自己的工作,该函数会将子线程的回收工作交给内核去做。

  2. pthread_self(); // 获取当前线程的ID

线程的状态

  1. 新建:新创建的一个线程。
  2. 就绪:准备运行的线程。
  3. 运行:正在运行的线程。
  4. 等待:也叫阻塞。
  5. 死亡:运行结束的线程。

多线程

同步与互斥

信号量

 

 互斥锁

pthread_mutex_destroy(pthread_mutex_t *mutex); 销毁锁。
pthread_mutex_lock(pthread_mutext_t *mutex); 上锁。
pthread_mutex_unlock(pthread_mutext_t *mutex); 解锁。
————————————————

传统的进程间的通信
无名管道

管道的创建是放在内存的内核区中,所以是不能很直观的看到管道的。

linux中管道也是文件。(管道文件)所以管道成功创建后会返回两个文件描述符,分别是读端和写端。(fd[0]读和fd[1]写)

一般来说两个进程一个发一个收,那么一端关闭fd[0]读操作,另一端关闭fd[1]写操作。

因为管道在内核区,用户对其操作只能用系统调用write和read操作,而不能用fwrite和fread

管道只能实现具有血缘关系的进程才能进行通信,否则会出现我创建的管道你找不到的情况。

管道的创建与关闭

 

有名管道(命名管道)

无名管道必须是有血缘关系的进程之间通信,但是实际情况并不是这样,现实中大多需要没有任何关系的进程间通信。这时就需要使用有名管道进行通信。

那么怎么能使不同进程间都找到这个管道呢?这时就有了管道文件,不同进程间可以通过对这个文件的读写来实现通信。

实际上这个管道文件存在于文件系统,这个文件的作用只是为了让没有血缘关系的两个进程能够找到存储在内核区中的同一个管道。读写的操作实际上还是通过内核区的管道。

把这个管道文件看作是内核区中的管道的名字以此来找到同一个内核区的管道,所以称其为有名管道。

  1. 特点:

    1. 可以实现任意两个进程之间的通信。
    2. 通信时双方通过一个管道文件进行操作,但实际上通过管道文件标识内核区管道来进行读写操作。这个文件的大小始终为0
    3. 管道文件是存在于文件系统中的。

 

 

 

 

  1. 信号量

    无名信号量:解决线程之间的同步与互斥。无名信号量的使用案例:

 

 

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

// 临界区:盘子
int plate = 4; // 最多只能放4个水果
int orange = 0; // 盘子中橘子的数量
int apple = 0; // 盘中苹果的数量

// 消费者最大值
int son_max = 5; // 儿子最多吃5个橘子
int girl_max = 5;// 女儿最多吃5个苹果

// 创建互斥锁,同一时刻只能有一个人放水果或拿水果
pthread_mutex_t production;
pthread_mutex_t consumer;

// 信号量
sem_t s_dad, s_mom, s_son, s_girl;

void* thread_dad(void *sp)
{
    while(1)
    {
        pthread_mutex_lock(&production);// 放水果占有盘子
        sem_wait(&s_dad);
        if(0 == son_max){
            printf("儿子吃饱了\n");
            sem_destroy(&s_son);
            pthread_mutex_unlock(&production);
            pthread_exit(NULL);
        }

        if(plate > 0){
            printf("爸爸放了一个橘子\n");
            --plate; // 盘子容量-1
            ++orange;// 橘子个数+1
        }
        else{
            printf("盘满了\n");
        }
        sem_post(&s_son); // 告诉儿子盘中有水果了
        pthread_mutex_unlock(&production);// 放完水果释放盘子
        sleep(1);
    }
    pthread_exit(NULL);
}

void* thread_mom(void *sp)
{
    while(1)
    {
        pthread_mutex_lock(&production);// 占用盘子放水果
        sem_wait(&s_mom);
        if(0 == girl_max){
            printf("女儿吃饱了\n");
            sem_destroy(&s_mom);
            pthread_mutex_unlock(&production);
            pthread_exit(NULL);
        }

        if(plate > 0){
            printf("妈妈放了一个苹果\n");
            --plate;// 盘子容量-1
            ++apple;// 苹果个数+1
        }
        else{
            printf("盘满了\n");
        }
        sem_post(&s_girl); // 告诉女儿盘中有水果了
        pthread_mutex_unlock(&production);// 释放盘子
        sleep(1);
    }
    pthread_exit(NULL);
}

void* thread_son(void *sp)
{
    while(1)
    {
        pthread_mutex_lock(&consumer);// 占用盘子拿橘子
        sem_wait(&s_son);

        if(plate == 4){
            printf("儿子说盘子空了\n");
            sem_post(&s_dad);// 通知爸爸放橘子
            pthread_mutex_unlock(&consumer);
            sleep(1);
            continue;
        }

        if(orange > 0){
            printf("儿子吃掉了一个橘子\n");
            ++plate;// 盘子容量+1
            --orange;// 橘子数量-1
            --son_max;//肚量-1
            if(son_max == 0){
                printf("吃饱了\n");
                pthread_mutex_unlock(&consumer);
                sem_post(&s_dad);// 告诉爸爸不要放橘子了
                sem_destroy(&s_son);// 不吃了
                pthread_exit(NULL);
            }
            sleep(1);
        }
        else{
            printf("没有橘子了\n");
            sleep(1);
        }
        sem_post(&s_dad);// 通知爸爸做橘子
        pthread_mutex_unlock(&consumer);// 释放拿的权限
        sleep(1);

    }
    pthread_exit(NULL);
}

void* thread_girl(void *sp)
{
    while(1)
    {
        pthread_mutex_lock(&consumer);// 占用盘子准备拿水果
        sem_wait(&s_girl);

        if(plate == 4){
            printf("女儿说盘子空了\n");
            sem_post(&s_mom);
            pthread_mutex_unlock(&consumer);
            sleep(1);
            continue;
        }
        if(apple > 0){
            printf("女儿吃掉了一个苹果\n");
            ++plate;// 盘子容量+1
            --apple;// 苹果数量-1
            --girl_max;// 肚量-1
            if(girl_max == 0){
                printf("吃饱了\n");
                pthread_mutex_unlock(&consumer);
                sem_post(&s_mom);// 告诉妈妈不要放苹果了
                sem_destroy(&s_girl);// 不吃了    
                pthread_exit(NULL);
            }
            sleep(1);
        }
        else{
            printf("盘中没有苹果了\n");
            sleep(1);
        }
        sem_post(&s_mom);// 通知妈妈放苹果
        pthread_mutex_unlock(&consumer);
        sleep(1);
    }
    pthread_exit(NULL);
}


int main()
{
    pthread_mutex_init(&production, NULL);
    pthread_mutex_init(&consumer, NULL);
    sem_init(&s_son, 0, 0);
    sem_init(&s_girl, 0, 0);
    sem_init(&s_dad, 0, 1);
    sem_init(&s_mom, 0, 1);

    // 生产者:爸爸往盘中放橘子,妈妈放苹果
    pthread_t dad = 1, mom = 2;
    pthread_create(&dad, NULL, thread_dad, NULL);// 爸爸
    pthread_create(&mom, NULL, thread_mom, NULL);// 妈妈


    // 消费者:儿子吃橘子,女儿吃苹果
    pthread_t son = 3, girl = 4;
    pthread_create(&son, NULL, thread_son, NULL);// 儿子
    pthread_create(&girl, NULL, thread_girl, NULL);// 女儿

    pthread_join(dad, NULL);
    pthread_join(mom, NULL);
    pthread_join(son, NULL);
    pthread_join(girl, NULL);

    pthread_mutex_destroy(&production);
    pthread_mutex_destroy(&consumer);

    return 0;
}

有名信号量:解决进程之间的同步与互斥。
1. 打开双方都认识的有名信号量文件(双方都可以创建)
2. P操作:sem_wait()
3. V操作:sem_post()
4. 关闭有名信号量:sem_close()
5. 删除创建的有名信号量:sem_unlink()
6. 有名信号量创建后在 /dev/shm 下

 

共享内存
其高效是因为,内核区内存的物理地址通过映射 到用户区的虚拟地址,用户通过该地址直接完成读写操作。

是一种最为高效的进程间通信方式,进程可以直接读写共享内存,而不需要任何数据的拷贝。
为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。
进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高效率。
由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。
共享内存中的数据是一直存在的除非删除这个共享内存,不像管道读完后管道中就没有数据了。
共享内存的使用
1. 创建/打开共享内存。ftok()函数产生key值,shmget()函数通过key值创建共享内存

映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问。

撤销共享内存映射。(也就是分离)

删除共享内存对象

消息队列

  1. 特点:
    1. 存储在内核中。
    2. 可以按照类型读取消息。
  2. 流程
    1. 产生key值。 ftok()函数

    2. 创建消息队列的通道。

添加消息。 

 

读取消息。

 

删除消息。

 

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

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

相关文章

WIN系统 -> CMD命令

查看哪个PID&#xff08;进程ID)--8001 netstat -ano | findstr :8001&#xff0c;然后查看哪个PID&#xff08;进程ID&#xff09;正在使用8001端口 手动结束进程

容器编排工具Docker Compose

目录 一、Docker Compose概述 1、主要功能 2、工作原理 二、常用命令参数 1、服务管理 2、构建和重新构建服务 三、Docker Compose的yml文件 1、服务 2、网络 3、存储卷 四、容器编排实现haproxy和nginx负载均衡 一、Docker Compose概述 1、主要功能 定义服务&#xf…

Linux系统进程控制

目录 一、进程创建 1.进程创建过程 2.写时拷贝 3.fork函数的两种常规用法 二、进程终止 1.进程终止的三种情况 2.进程退出信息 &#xff08;1&#xff09;退出码 &#xff08;2&#xff09;退出信号 3.进程终止的方式 三、进程等待 1.为什么要有进程等待&#xff1f…

成都睿明智科技有限公司赋能商家高效变现

在这个日新月异的数字时代&#xff0c;抖音电商正以不可阻挡之势崛起&#xff0c;成为众多品牌与商家竞相角逐的新战场。在这片充满机遇与挑战的蓝海中&#xff0c;成都睿明智科技有限公司如同一颗璀璨新星&#xff0c;凭借其专业的服务、创新的策略和敏锐的市场洞察&#xff0…

C++你不得不知道的(1)

C你不得不知道的&#xff08;1&#xff09; 【1】引例&#xff1a; 1、C语言在使用的过程中存在冲突问题&#xff01; 解决办法&#xff1a;使用域将想要使用的变量包括进去。 #include<stdio.h> int rand10; int main() {printf("%d\n",rand);return 0; }此…

VS Code激活python虚拟环境常见报错

VS Code激活python虚拟环境常见报错 问题1&#xff1a;执行激活 activate 报错 问题1&#xff1a;执行激活 activate 报错 解决&#xff1a; Win X *执行 set-executionpolicy remotesigned 再输入 Y

【智慧城市】新中地GIS开发实训项目:华农优秀学生学习成果展示(3)智游江城

华农GIS开发实训项目答辩③-智游江城/一个月学习成果展示 项目名称&#xff1a;智游江城 项目功能 主页面展示 菜单功能 控制台 3D城市 查询 导航 游览路线推荐 测量 资讯

Colorful/七彩虹将星X15 AT 23 英特尔13代处理器 Win11原厂OEM系统 带COLORFUL一键还原

安装完毕自带原厂驱动和预装软件以及一键恢复功能&#xff0c;自动重建COLORFUL RECOVERY功能&#xff0c;恢复到新机开箱状态。 【格式】&#xff1a;iso 【系统类型】&#xff1a;Windows11 原厂系统下载网址&#xff1a;http://www.bioxt.cn 注意&#xff1a;安装系统会…

DataWhale x南瓜书学习笔记 task04笔记

线性判别分析&#xff08;LDA&#xff09; 前提假设&#xff1a;各类样本的协方差矩阵相同且满秩LDA的思想&#xff1a;1.设法让训练样例集投影到一条直线上&#xff0c;2.同类样例的投影点尽可能接近&#xff0c;异类样例的投影点尽可能远离&#xff0c;3.在对新样本进行分类时…

嘻哈纸片人仿手绘插画!FLUX一键生成方法!

​ ​ ​ 如何生成这种嘻哈纸片人的仿手绘插画&#xff1f; 只需1个lora&#xff0c;3个步骤&#xff01; 接下来我们来具体的说一下操作方法以及lora使用注意 嘻哈纸片人lora 基于FLUX模型训练 在线使用&下载地址&#xff1a; https://www.liblib.art/modelinfo/53ee…

全新一区PID搜索算法+TCN-LSTM+注意力机制!PSA-TCN-LSTM-Attention多变量时间序列预测(Matlab)

全新一区PID搜索算法TCN-LSTM注意力机制&#xff01;PSA-TCN-LSTM-Attention多变量时间序列预测&#xff08;Matlab&#xff09; 目录 全新一区PID搜索算法TCN-LSTM注意力机制&#xff01;PSA-TCN-LSTM-Attention多变量时间序列预测&#xff08;Matlab&#xff09;效果一览基本…

网络与信息安全工程师(工信部教育与考试中心)

在当今数字化时代&#xff0c;大量的敏感信息与业务流程在网络上传输和处理&#xff0c;使得网络与信息安全成为保障企业运营、政务管理以及金融交易等关键领域不可忽视的一环。 因此&#xff0c;对网络安全专家的需求日益增长。 例如&#xff0c;金融机构、大型电信运营商以…

【AI战略思考5】工欲善其事,必先利其器。我的利器是什么?

目录 导言1.不要忽视时间本身复利的巨大威力2.只赚自己认知以内的钱&#xff0c;只把握自己能力以内的机会3.多做有难度的事来激发自己的潜力和提升自己4.学会抵制诱惑5.减少冗余思考和冗余操作 导言 工欲善其事&#xff0c;必先利其器。我的利器是什么&#xff1f; 虽然我中考…

从零开始搭建UVM平台(二)-加入factory机制

书接上回&#xff1a; 从零开始搭建UVM平台&#xff08;一&#xff09;-只有uvm_driver的验证平台 加入factory机制 前面搭建的平台其实一点都没有用到uvm的特性。 加入factory机制的明显两个优点&#xff1a;&#xff08;1&#xff09;不用自己手动例化类&#xff1b;&…

目标价已被华尔街投行大幅下调,Workday股票还能买入吗?

猛兽财经核心观点&#xff1a; &#xff08;1&#xff09;Needham已经将Workday的目标价下调至300美元&#xff0c;但维持“买入”评级。 &#xff08;2&#xff09;Workday第二季度的财务业绩虽然很强劲的&#xff0c;但面临客户群员工增长疲软挑战。 &#xff08;3&#xff0…

C语言语句、语句分类及注释

文章目录 一、语句和语句分类二、注释&#x1f355;注释是什么&#xff1f;为什么写注释&#xff1f;1. /**/的形式2. //的形式3. 注释会被替换 三、随机数的生成1.rand函数2.srand函数3.time函数4.设置随机数的范围 四、C99中的变长数组五、问题表达式解析表达式1表达式2表达式…

嵌入式的核心能力-Debug调试能力(一)

一、栈回溯 引入&#xff1a;调试程序时&#xff0c;经常会发生这类错误&#xff1a; 读写某个地址&#xff0c;程序报错&#xff1b;调用某个空函数&#xff0c;导致程序报错等等。 解决方法是&#xff0c;可以利用异常处理函数去打印出“发生错误瞬间”的所有寄存器地址 …

网络编程(1)——同步读写api

一、day1 学习了服务器和客户端socket的建立、监听以及连接。 &#xff08;1&#xff09;socket的监听和连接 服务端 1&#xff09;socket——创建socket对象。 2&#xff09;bind——绑定本机ipport。 3&#xff09;listen——监听来电&#xff0c;若在监听到来电&#x…

人脸遮挡检测系统源码分享

人脸遮挡检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

基于微信小程序的特色乡村综合展示平台设计与实现(源码+文档+讲解开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…