嵌入式学习-IO进程-Day05

devtools/2024/10/19 22:30:30/

嵌入式学习-IO进程-Day05

线程函数接口

线程回收函数

获取线程号

线程同步

概念

线程同步机制

信号量

无名信号量

函数接口

互斥

互斥的概念

互斥锁

函数接口

死锁(面试可能会问)

条件变量

使用步骤

函数接口

进程间通信

Linux/Unix平台的通信方式发展

进程间的通信方式

线程函数接口

线程回收函数

 int pthread_join(pthread_t thread, void **retval);
功能:用于等待一个指定的线程结束,阻塞函数
参数:thread:创建的线程对象 void **retval: 指针*retval指向线程返回的参数,一般是NULL
返回值:成功 : 0
       失败:errnoint pthread_detach(pthread_t thread);
功能:让线程结束时自动回收线程资源,让线程和主线程分离
参数:thread:线程ID
返回值:成功 : 0
       失败:errno

示例代码:

获取线程号

pthread_t pthread_self(void);
功能:
    获取线程号
返回值:
    成功:调用此函数线程的ID

线程同步

线程之间是很容易进行通信的,能够通过全局变量实现数据的共享和交换,也就是通过访问临界资源,但是多个线程在同时访问共享数据的对象时需要引入同步和互斥机制。

临界资源:一次仅允许一个线程访问的资源。

概念

同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情

线程同步机制

信号量

内核信号量

由内核控制路径使用

Posix信号量

a.无名信号量:数据存储在内存中,通常在线程间使用或父子进程间

函数接口:sem_init\sem_wait\sem_post

b.有名信号量:数据存储在文件中,在进程间线程间都可以使用

函数接口:sem_open\sem_wait\sem_post\sem_close

System V信号量

是信号量的集合,叫信号灯集,属于IPC对象

函数接口:semget\semctl\semop

无名信号量

信号量:通过信号量实现同步操作,由信号量决定线程是继续运行还是阻塞等待。

信号量代表的是某一类资源,它的值表示系统中该资源的数量,信号量>0的话,表示有资源可以使用,可以申请到资源,继续执行程序,信号量<= 0的话,表示没有资源可以使用,无法申请到资源,阻塞。

信号量是一个受保护的量,只能通过三种操作来访问:

  1. 初始化信号量:sem_init()
  2. P操作,申请资源:sem_wait() 资源-1
  3. V操作,释放资源:sem_post() 资源+1

注意:信号量是一个非负的整数,所以一定是>=0的。

函数接口
int  sem_init(sem_t *sem,  int pshared,  unsigned int value)  
功能:初始化信号量   
参数:sem:初始化的信号量对象
    pshared:信号量共享的范围(0: 线程间使用   非0:1进程间使用)
    value:信号量初值
返回值:成功 0
      失败 -1获取信号量的值:sem_getvalue();int  sem_wait(sem_t *sem)  
功能:申请资源  P操作 
参数:sem:信号量对象
返回值:成功 0
      失败 -1
注:此函数执行过程,当信号量的值大于0时,表示有资源可以用,则继续执行,同时对信号量减1;当信号量的值等于0时,表示没有资源可以使用,函数阻塞int  sem_post(sem_t *sem)   
功能:释放资源  V操作      
参数:sem:信号量对象
返回值:成功 0
      失败 -1
注:释放一次信号量的值加1,函数不阻塞

示例代码:

练习:创建一个线程,一个从终端输入,另一个线程从终端输出。输入quit退出

#include <stdio.h>
#include <semaphore.h>
#include <pthread.h>
#include <string.h>
char buf[32];
sem_t sem;
void *my_print(void *arg)
{
    while (1)
    {
        sem_wait(&sem);                //信号量:0
        if (!strcmp(buf,"quit"))
        {
           pthread_exit(NULL);
        }
        printf("buf:%s\n",buf);
    }
}
int main(int argc, char const *argv[])
{    int sval;
    // 初始化信号量
    if (sem_init(&sem, 0, 0))        //信号量:0
    {
        printf("sem_init err\n");
        return -1;
    }
    pthread_t tid;
    // 创建线程
    if (pthread_create(&tid, NULL, my_print, NULL))
    {
        printf("create err\n");
        return -1;
    }
    // 循环从终端获取内容
    while (1)
    {
        fgets(buf, 32, stdin);
        // 换行变成结束
        if (buf[strlen(buf) - 1] == '\n')
        {
            buf[strlen(buf) - 1] = '\0';
        }
        sem_post(&sem); 
        if (!strcmp(buf, "quit"))
        {
            break;
        }    
    }
    //回收线程
    pthread_join(tid,NULL);
    return 0;
}

互斥

互斥的概念

多个线程在访问临界资源时,同一时间只能一个线程进行访问

互斥锁

互斥锁:通过互斥锁可以实现互斥机制,主要用来保护临界资源,每个临界资源都由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。

函数接口

int  pthread_mutex_init(pthread_mutex_t  *mutex, pthread_mutexattr_t *attr)  
功能:初始化互斥锁  
参数:mutex:互斥锁
    attr:  互斥锁属性  //  NULL表示缺省属性
返回值:成功 0
      失败 -1int  pthread_mutex_lock(pthread_mutex_t *mutex)   
功能:申请互斥锁     
参数:mutex:互斥锁
返回值:成功 0
      失败 -1int  pthread_mutex_unlock(pthread_mutex_t *mutex)   
功能:释放互斥锁     
参数:mutex:互斥锁
返回值:成功 0
      失败 -1int  pthread_mutex_destroy(pthread_mutex_t  *mutex)  
功能:销毁互斥锁     
参数:mutex:互斥锁

练习:两个线程(除了主线程)实现一个循环倒置,一个循环打印。

int a[10]={0,1,2,3,4,5,6,7,8,9};

#include <stdio.h>
#include <pthread.h>
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
pthread_mutex_t lock;
void *myprint(void *arg)
{
    while (1)
    {
        // 上锁
        pthread_mutex_lock(&lock);
        // 循环打印
        for (int i = 0; i < 10; i++)
        {
            printf("%d ", a[i]);
        }
        printf("\n");
        // 解锁
        pthread_mutex_unlock(&lock);
        // 一秒打印一次
        sleep(1);
    }
}
void *myrever(void *arg)
{
    // 循环倒置
    int temp;
    while (1)
    {
        // 上锁
        pthread_mutex_lock(&lock);
        for (int i = 0; i < 5; i++)
        {
            temp = a[i];
            a[i] = a[9 - i];
            a[9 - i] = temp;
        }
        // 解锁
        pthread_mutex_unlock(&lock);
    }
}
int main(int argc, char const *argv[])
{
    // 初始化锁
    if (pthread_mutex_init(&lock, NULL))
    {
        printf("init err\n");
        return -1;
    }
    // 标识两个线程
    pthread_t tid1, tid2;
    // 创建两个线程
    if (pthread_create(&tid1, NULL, myrever, NULL))
    {
        perror("create err");
        return -1;
    }
    if (pthread_create(&tid2, NULL, myprint, NULL))
    {
        perror("create err");
        return -1;
    }
    // 回收线程资源
    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
    return 0;
}

死锁(面试可能会问)

概念:

是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去

产生死锁的原因:

1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

注意:当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。

条件变量

一般与互斥锁搭配使用,搭配互斥锁可以实现同步机制。

使用步骤

  1. pthread_cond_init:初始化
  2. pthread_cond_wait:阻塞等待条件产生,没有条件产生时阻塞,同时解锁,当条件产生时结束阻塞,再次上锁
  3. pthread_cond_signal:产生条件,不阻塞

pthread_cond_wait先执行,pthread_cond_signal再产生条件

函数接口

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能:初始化条件变量
参数:cond:是一个指向结构pthread_cond_t的指针
    restrict attr:是一个指向结构pthread_condattr_t的指针,一般设为NULL
返回值:成功:0 失败:非0int pthread_cond_wait(pthread_cond_t *restrict cond,    pthread_mutex_t *restrict mutex);
功能:等待信号的产生
参数:restrict cond:要等待的条件
     restrict mutex:对应的锁
返回值:成功:0,失败:不为0
注:当没有条件产生时函数会阻塞,同时会将锁解开;如果等待到条件产生,函数会结束阻塞同时进行上锁。int pthread_cond_signal(pthread_cond_t *cond);
功能:给条件变量发送信号
参数:cond:条件变量值
返回值:成功:0,失败:非0
注:必须等待pthread_cond_wait函数先执行,再产生条件才可以int pthread_cond_destroy(pthread_cond_t *cond);
功能:将条件变量销毁
参数:cond:条件变量值
返回值:成功:0, 失败:非0

进程间通信

Linux/Unix平台的通信方式发展

早期通信方式

AT&T的贝尔实验室,对Unix早期的进程间通信进行了改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内。IPC:InterProcess Communication

BSD(加州大学伯克利分校的伯克利软件发布中心),跳过了只能在同一计算机通信的限制,形成了基于套接字(socket)的进程间通信机制。

进程间的通信方式

1)早期的进程间通信:

无名管道(pipe)、有名管道(fifo)、信号(sem)

2)systerm V IPC对象:

共享内存(share memory)、消息队列(message queue)、信号灯(semaphore)

3)BSD:

套接字(socket)


http://www.ppmy.cn/devtools/127113.html

相关文章

基于SpringBoot+Vue+uniapp的在线招聘平台的详细设计和实现

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

JAVA队列

目录 1. 队列(Queue) 2.1 概念 2.2 队列的使用 ​编辑 ​编辑 后入后出 和栈类似 队列同样有 size&#xff08;&#xff09; 和 empty&#xff08;&#xff09;方法 2.3 队列模拟实现 3. 出队列 1. 队列(Queue) 1.1 概念 队列&#xff1a;只允许在一端进行插入数据…

【Vue进阶】第一章——熟悉Vue常用指令:从文本插值到表单绑定

目录 内容主要包含 1.Vue 常用指令介绍 目标 内容讲解 内容小结 2.文本插值v-html 目标 内容讲解 内容小结 3.绑定属性 v-bind:属性名或者 :属性名 (重点) 目标 内容讲解 内容小结 4.条件渲染v-if 目标 内容讲解 内容小结 5.条件渲染v-show 目标 内容讲解…

JavaWeb 19 AJAX

目录 一、什么是AJAX 同步交互和异步交互 同步交互 异步交互 Ajax工作原理 Ajax实现方式 原生JavaScript方式进行ajax(了解)&#xff1a; "我就是希望你好&#xff0c;就像很多人希望我好一样&#xff0c;特别简单&#xff0c;特别真挚。也不为了什么&#xff0c;就是希望…

CST软件超表面--- 偏振片- 线圆极化转换,Floquet端口,S参数算轴比AR

这期我们看一个超表面极化分析&#xff0c;用到Floquet端口模数&#xff0c;S参数读出极化和轴比&#xff0c;还有平面波散射截面等技巧。 使用模板&#xff0c;频率0-25GHz&#xff0c;电场监视器8.06GHz: 画一片PEC&#xff1a; 画第二片PEC&#xff0c;insert到第一片里面&…

ECU 安全启动和安全刷写的技术实现演示案例

场景: 诊断仪将新的应用程序软件下载到ECU中。 假设条件: ECU硬件支持CAN通信。ECU已安装Bootloader软件。诊断仪支持UDS协议和所需的诊断服务。应用程序软件已打包成HEX格式文件。 流程步骤: 预编程步骤: STP1_a: 切换扩展会话 诊断仪发送: $10 03 (功能寻址)ECU响应: $5…

网络空间安全之一个WH的超前沿全栈技术深入学习之路(一:渗透测试行业术语扫盲)作者——LJS

欢迎各位彦祖与热巴畅游本人专栏与博客 你的三连是我最大的动力 以下图片仅代表专栏特色 [点击箭头指向的专栏名即可闪现] 专栏跑道一 ➡️网络空间安全——全栈前沿技术持续深入学习 专栏跑道二➡️ 24 Network Security -LJS ​ ​ ​ 专栏跑道三 ➡️ MYSQL REDIS Advanc…

RabbitMQ 入门(六)SpringAMQP五种消息类型(Direct Exchange)

一、发布订阅-DirectExchange&#xff08;路由模式&#xff09; 在Fanout模式中&#xff0c;一条消息&#xff0c;会被所有订阅的队列都消费。但是&#xff0c;在某些场景下&#xff0c;我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。 Direct Exchan…