嵌入式学习——Linux高级编程复习(互斥锁、信号量、管道、信号)——day41

news2024/12/28 17:37:55

1. 同步和异步

1.1 同步

        多个任务在某一时刻,先后执行顺序可以被确定

        同步操作要求一系列操作严格按照顺序执行,一个操作只有在前一个操作完成之后才能开始。在计算机编程中,这意味着当一个程序或线程发出一个请求或调用后,它会暂停执行,直到该请求完成并返回结果,这个过程通常称为阻塞。

1.2 异步

        多个任务执行顺序相互独立,没有先后顺序关系

        异步操作则允许一个操作开始后,调用者不必等待其完成就可以继续执行其他任务。这意味着操作的完成和结果的获取是分开的,结果通常通过回调函数、事件、消息队列或其他形式的通知机制来传达给调用者。异步机制提高了程序的并发性和响应性,因为它允许程序在等待某个慢速操作(如I/O操作)的同时处理其他任务。

1.3 总结

        简而言之,同步强调操作的顺序执行和相互等待,而异步则允许操作并发执行,无需等待其他操作的完成。

2. 互斥锁、信号量、管道、信号的区别和联系

2.1 互斥锁

        主要用于线程间的同步通信

        确保同一时间只有一个线程可以访问共享资源。虽然在某些操作系统中,通过特定的属性设置,互斥锁可以跨进程使用,但其主要应用场景是线程同步。

2.2 信号量

        既可用于线程间同步,也可用于进程间同步。也可以用于进程或线程的异步通信。

        信号量可以控制对共享资源的访问数量,是一种更为灵活的同步机制,支持跨进程的同步需求。

2.3 管道

        通常用于在具有亲缘关系的进程间(如父子进程)进行同步数据传输。

        匿名管道是半双工的,数据只能单向流动,且主要用于进程间通信。虽然管道不直接用于线程间通信,但在某些系统中,通过进程间通信方式间接实现线程间的数据交换也是可能的。

2.4 信号

        主要用于进程间的异步通信。

        用于通知接收进程某个事件的发生,如终端用户请求中断进程。信号不是用于数据传输,而是简单事件的传递,且是异步的,即发送信号不需要等待接收方的响应。

2.5 总结

        综上所述

        1. 进程线程:信号量是唯一明确既适用于线程间又适用于进程间通信的机制。互斥锁主要针对线程同步,但特定条件下也能用于进程同步。管道主要用于进程间通信,特别是具有血缘关系的进程,而信号则是进程间的异步通信方式。

        2. 同步异步:互斥锁和管道主要是同步通信机制,信号量依据使用场景既可同步也可异步,而信号则是典型的异步通信方式。

3. 原子操作

        原子操作(Atomic Operation)是指在计算机科学中,那些不可中断的操作序列,这些操作要么全部完成要么完全不执行,不存在执行到一半的状态。这意味着在多线程环境或并发处理时,一个原子操作不会受到其他线程的干扰,保证了操作的完整性和一致性。

        不能被CPU任务调度所打断的一次最小的操作      

4. 死锁

4.1 定义

            多线程任务由于加锁导致均无法向下执行的状态,称为死锁

4.2 死锁产生的四个必要条件

        1.互斥条件
        2.不可剥夺条件
        3.请求保持
        4.循环等待

4.3 死锁解决办法

        1.破坏不可剥夺条件
        2.使用pthread_mutex_trylock替代pthread_mutex_lock 
        3.加锁和解锁顺序保持一致

5. 互斥锁

5.1 引用互斥锁的原因:利用全局变量能够实现两个线程任务通信,线程任务通信操作全局变量可能会引发资源竞争,为避免资源竞争,引入互斥锁机制

5.2 定义

        互斥锁可以理解为是一种资源,一旦互斥锁被加锁,另外的线程任务无法继续加锁,必须等待互斥锁被解锁,另外的任务才能加锁

5.3 临界资源(临界区)

          加锁和解锁中间的代码(资源)称为临界资源(临界区),同一时刻,临界资源不能被同时执行

6. 互斥锁相关函数接口

6.1  pthread_mutex_init

        1. 定义

        2. 功能

                    初始化一个互斥锁 

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

6.2  pthread_mutex_lock

        1. 定义

        2. 功能

                    上锁

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

6.3  pthread_mutex_unlockk

        1. 定义

        2. 功能

                解锁

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

6.4  pthread_mutex_destroy

        1. 定义

        2. 功能

                销毁锁资源

        3. 参数

        4. 返回值

        5. 示例程序

#include "head.h"

pthread_mutex_t lock;
int value1 = 0;
int value2 = 0;
int num = 0;

void *thread1(void *arg)
{
	while (1)
	{
		pthread_mutex_lock(&lock);
		value1 = num;
		value2 = num;
		pthread_mutex_unlock(&lock);
		num++;
	}

	return NULL;
}

void *thread2(void *arg)
{
	while (1)
	{
		pthread_mutex_lock(&lock);
		if (value1 != value2)
		{
			printf("value1 = %d, value2 = %d\n", value1, value2);	
		}
		pthread_mutex_unlock(&lock);
	}

	return NULL;
}

int main(int argc, char const *argv[])
{
	pthread_t tid1;
	pthread_t tid2;

	pthread_mutex_init(&lock, NULL);
	pthread_create(&tid1, NULL, thread1, NULL);
	pthread_create(&tid2, NULL, thread2, NULL);

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	pthread_mutex_destroy(&lock);

	return 0;
}

        6. 注意

7.信号量

7.1 定义

        信号量是一种资源,可以被初始化,申请和释放

7.2 PV操作

        P申请、V释放

8. 信号量函数接口

8.1 sem_init

        1. 定义

        2. 功能

                    对信号量初始化

        3. 参数

        4. 返回值

        5. 示例代码

        6. 注意

8.2 sem_post

        1. 定义

        2. 功能

                    释放一个信号量(让资源数+1)

        3. 参数

        4. 返回值

        5. 示例代码

        6. 注意

8.3 sem_wait

        1. 定义

        2. 功能

                    申请信号量(让资源数-1),如果资源数为0,阻塞等待有人释放资源(资源数>0),才能申请
                    资源继续向下执行

        3. 参数

        4. 返回值

        5. 示例代码

        6. 注意

8.4 sem_destroy

        1. 定义

        2. 功能

                    销毁信号量

        3. 参数

        4. 返回值

        5. 示例代码

#include "head.h"

char tmpbuff[4096] = {0};

sem_t sem_w;
sem_t sem_r;

void *readfun(void *arg)
{
	while (1)
	{
		sem_wait(&sem_r);
		printf("tmpbuff = %s\n", tmpbuff);
		sem_post(&sem_w);
	}

	return NULL;
}

void *writefun(void *arg)
{
	while (1)
	{
		sem_wait(&sem_w);
		gets(tmpbuff);
		sem_post(&sem_r);
	}

	return NULL;
}

int main(int argc, char const *argv[])
{
	pthread_t tid_w;
	pthread_t tid_r;

	sem_init(&sem_r, 0, 0);
	sem_init(&sem_w, 0, 1);
	pthread_create(&tid_r, NULL, readfun, NULL);
	pthread_create(&tid_w, NULL, writefun, NULL);

	pthread_join(tid_r, NULL);
	pthread_join(tid_w, NULL);
	sem_destroy(&sem_w);
	sem_destroy(&sem_r);

	return 0;
}

        6. 注意

9. 管道——windows中无管道文件

 9.1 无名管道:具有亲缘关系的进程间通信——父子进程、爷孙进程

9.2 有名管道:用于任意两个进程间通信

10. 无名管道(fork后子进程会继承父进程的文字描述符,实现父子进程的通信)

10.1 函数接口

        pipie

        1. 定义

i                nt pipe(int pipefd[2]);

        2. 功能

                        创建一个用来通信的无名管道(在内核中)

        3. 参数

                pipefd:存放文件描述符数组空间首地址
                    pipefd[0]:读管道文件描述符
                    pipefd[1]:写管道文件描述符        

        4. 返回值       

                 成功返回0 
                 失败返回-1 

        5. 示例程序        

#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
    pid_t pid;
    char tmpbuff[4096] = {0};
    int pipefd[2] = {0};
    int ret = 0;

    ret = pipe(pipefd);
    if (-1 == ret)
    {
        perror("pipe error!\n");
        return -1;
    }

    pid = fork();
    if (-1 == pid)
    {
        perror("fork error!\n");
        return -1;
    }

    if (0 == pid)
    {
        strcpy(tmpbuff, "hello world");
        write(pipefd[1], tmpbuff, strlen(tmpbuff)+1);
    }
    else if (pid > 0)
    {
        read(pipefd[0], tmpbuff, sizeof(tmpbuff));
        printf("tmpbuff = %s\n", tmpbuff);
    }

    return 0;
}

 10.2 无名管道中的四种特殊情况

        1. 管道中至少有一个写端:

                1.如果管道中有数据,直接读取 
                2.如果管道中没有数据,阻塞等待,直到有数据写入,再读取数据

        2. 管道中没有写端

                1.如果管道中有数据,直接读取
                2.如果管道中没有数据,不阻塞等待,直接返回

        3. 管道中至少有一个读端

                1.向管道中写入数据,如果没有写满,则直接写入
                2.如果写满(64k),阻塞等待数据读出,才能继续写入

        4. 管道中没有读端

                1.向管道中写入数据会产生管道破裂的错误

11. 有名管道函数接口

        mkfifo

        1,定义

                      int mkfifo(const char *pathname, mode_t mode);

        2. 功能

                        创建一个有名管道

        3. 参数

                pathname:有名管道的路径
                mode:有名管道的权限

        4. 返回值

                成功返回0 
                失败返回-1  

        5.示例程序

                1. 头文件

#ifndef __HEAD_H__
#define __HEAD_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>

#endif

                2.makefile

all:read write 

read:read.c
	gcc read.c -o read
write:write.c
	gcc write.c -o write 
.PHONY:
clean:
	rm read write 

                3. read.c

#include "head.h"

int main(int argc, char const *argv[])
{
	int fd = 0;
	char tmpbuff[4096] = {0};

	fd = open("/tmp/myfifo", O_RDONLY);
	if (-1 == fd)
	{
		perror("fail to open");
		return -1;
	}
	printf("管道打开成功!\n");

	read(fd, tmpbuff, sizeof(tmpbuff));
	printf("RECV:%s\n", tmpbuff);

	close(fd);

	return 0;
}

                4. write.c

#include "head.h"

int main(int argc, char const *argv[])
{
	int fd = 0;
	char tmpbuff[4096] = {0};

	mkfifo("/tmp/myfifo", 0777);

	fd = open("/tmp/myfifo", O_WRONLY);
	if (-1 == fd)
	{
		perror("fail to open");
		return -1;
	}
	printf("管道打开成功!\n");

	gets(tmpbuff);
	write(fd, tmpbuff, strlen(tmpbuff)+1);

	close(fd);

	return 0;
}

        6. 注意

               有名管道必须读写两端同时加入后才能继续向下执行,否则以只读或只写方式打开,会发生阻塞(等待另一端的加入)

12. 信号

12.1 定义

        内核层给用户层传递消息,通过发送信号实现

12.2 信号类型

        kill -l 
         1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
         6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
        11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
        16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
        21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
        26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
        31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
        38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
        43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
        48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
        53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
        58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
        63) SIGRTMAX-1    64) SIGRTMAX    
        
        SIGINT:中断信号(可以在终端按ctrl + c输入)
        SIGQUIT:退出信号(可以在终端按ctrl + \输入)
        SIGKILL:杀死信号
        SIGSEGV:段错误信号
        SIGPIPE:管道破裂信号
        SIGALRM:定时信号
        SIGCHLD:当前进程有子进程结束(子进程结束,操作系统会给父进程发送SIGCHLD)
        SIGCONT:继续执行信号
        SIGSTOP:暂停信号
        SIGIO:异步IO信号
        SIGTSTP:挂起信号(可以在终端按ctrl + z输入)

12.3 信号处理方式

        1.缺省(按照默认处理方式)
        2.忽略(不响应信号)
        3.捕捉(按自定义方式处理信号)

        注意:

             9号:SIGKILL
            19号:SIGSTOP 
            不能被忽略和捕捉

13. 信号函数接口

13.1 signal

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

13.2 pause

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

13.3 raise

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

13.4 alarm

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

13.5 kill

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

        6. 注意

13.1 signal

        1. 定义

        2. 功能

        3. 参数

        4. 返回值

        5. 示例程序

#include "head.h"

pid_t pid;

void handler_child(int signo)
{
	if (SIGINT == signo)
	{
		printf("爸,我回来了!\n");
		kill(getppid(), SIGUSR1);
	}
	else if (SIGUSR2 == signo)
	{
		printf("哦\n");
	}

	return;
}

void handler_father(int signo)
{
	if (SIGUSR1 == signo)
	{
		printf("快去写作业!\n");
	}
	else if (SIGQUIT == signo)
	{
		printf("儿子,我回来了\n");
		kill(pid, SIGUSR2);
	}

	return;
}

int main(int argc, char const *argv[])
{
	pid = fork();
	if (-1 == pid)
	{
		perror("fail to fork");
		return -1;
	}
	if (0 == pid)
	{
		signal(SIGINT, handler_child);
		signal(SIGQUIT, SIG_IGN);
		signal(SIGUSR2, handler_child);
	}
	else if (pid > 0)
	{
		signal(SIGINT, SIG_IGN);
		signal(SIGUSR1, handler_father);
		signal(SIGQUIT, handler_father);
	}

	while (1)
	{
		
	}

	return 0;
}

        6. 注意

        


 

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

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

相关文章

java自动化之java基础03-09java基础之数组

数组 1、定义 数组是一种用于存储固定大小的同类型数据的数据结构 1&#xff09;固定大小 2&#xff09;同类型数据的存储 2、声明数组 1&#xff09;数据类型[] 变量名称&#xff1b; 例如&#xff1a;int[] numsArry; 2&#xff09;数据类型 变量名称[]; 例如&#xf…

27.机会成本

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/677 题目描述 明天有 𝑛n 门考试,今晚只…

【C++修行之道】类和对象(五)日期类的实现、const成员、取地址及const和取地址操作符重载

目录 一、 日期类的实现 Date.h 1.1 GetMonthDay函数&#xff08;获取某年某月的天数&#xff09; 问&#xff1a;这个函数为什么不和其他的函数一样放在Date.cpp文件中实现呢&#xff1f; 1.2 CheckDate函数&#xff08;检查日期有效性&#xff09;、Print函数&#xff08;…

计算机毕业设计 | SpringBoot宠物医院管理 宠物商城购物系统(附源码)

写在前面 Le Dao宠物医院管理系统是一个超大型的&#xff0c;完成度很高的&#xff0c;集宠物医疗、宠物美容、宠物交易、宠物周边等各种功能于一身的&#xff0c;权限涵盖普通用户、医生、化验师、美容师、仓库主管、采购员等多种角色于一体的大型宠物医疗&#xff0c;购物系…

Java 数据类型 -- Java 语言的 8 种基本数据类型、字符串与数组

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 004 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

1035 插入与归并(测试点6)

solution 类型判断&#xff1a;插入排序中已排序的部分有序&#xff0c;未排序的和原数组元素相同&#xff1b;否则为归并排序测试点6&#xff1a;对于归并排序的子序列长度&#xff0c;不能简单视为前k个有序则子序列长度就是k 例如该测试用例的归并排序的子序列长度应该为2&…

重新认识Word —— 制作简历

重新认识Word —— 制作简历 PPT的图形减除功能word中的设置调整页边距进行排版表格使用 我们之前把word长排版文本梳理了一遍&#xff0c;其实word还有另外的功能&#xff0c;比如说——制作简历。 在这之前&#xff0c;我们先讲一个小技巧&#xff1a; PPT的图形减除功能 …

记录一次被谷歌封号后又解封的过程

先提前恭祝2024年所有参加高考的学子们都能金榜题名&#xff0c;会的全对&#xff0c;不会的蒙的全对&#xff01; 一、背景 众所周知&#xff0c;谷歌、ios应用市场对app的审查都是极其严格的&#xff0c;开发者稍有不慎就会被谷歌下架应用&#xff0c;乃至封号。我们公司是做…

目标检测应用场景—数据集【NO.36】甘蔗叶片病害识别数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

error while loading shared libraries 找不到动态库问题如何解决

在使用 c 或 c 开发应用时&#xff0c;在启动程序时&#xff0c;有时会遇到这个错误&#xff0c;找不到动态库。这个时候&#xff0c;我们使用 ldd 来查看&#xff0c;发现可执行文件依赖的动态库显示为 not found。 1 实验代码 使用如下 3 个文件做实验。 hello.h 中声明了函…

Mysql使用中的性能优化——搭建Mysql的监测服务

大纲 环境安装配置Mysql安装设置root密码新增远程访问账户修改绑定地址重启 新增 MySQL Server Exporter 用户 安装启动mysqld_exporter安装启动新增配置启动直接启动以Service形式启动 安装启动Prometheus创建用户下载并解压修改配置启动 安装启动grafana安装启动 测试参考资料…

地图商家数据怎么查看?揭秘采集软件工作原理!

地图商家数据怎么查看&#xff1f;其实主要就是两种方法&#xff1a; 1. 直接使用地图服务提供的API&#xff1a;大多数地图提供商&#xff08;如Google地图&#xff0c;百度地图等&#xff09;都会提供一些API&#xff0c;通过这些API&#xff0c;可以获取到它们所拥有的商家…

速卖通如何放关联?

大家都知道&#xff0c;想要进行多账号操作必须一再小心&#xff0c;否则会有很大的关联风险&#xff0c;而账号关联所带来的后果是卖家绝对不能轻视的&#xff0c;严重的话会导致封号&#xff0c;这样一来自己前期的辛苦运营就全都打水漂了&#xff0c;因此防关联很重要&#…

vue处理json数据

背景&#xff1a;后端返回的数据不是我想要的&#xff0c;现在需要把 name 替换为title&#xff08;小声蛐蛐&#xff1a;又让我处理数据&#xff09; 后端返回数据格式 修改字段操作&#xff1a;&#xff08;使用递归遍历的方式将title属性赋了name的值&#xff09; renderT…

转让北京劳务分包地基基础施工资质条件和流程

地基基础资质转让流程是怎样的?对于企业来说&#xff0c;资质证书不仅是实力的证明&#xff0c;更是获得工程承包的前提。而在有了资质证书后&#xff0c;企业才可以安心的准备工程投标&#xff0c;进而在工程竣工后获得收益。而对于从事地基基础工程施工的企业&#xff0c;需…

gpt、llama大模型模型结构细节探索

参考&#xff1a; https://github.com/naklecha/llama3-from-scratch&#xff08;一定要看看&#xff09; https://github.com/karpathy/build-nanogpt/blob/master/play.ipynb 视频&#xff1a; https://www.youtube.com/watch?vl8pRSuU81PU https://tiktokenizer.vercel…

基于python-CNN深度学习的水瓶是否装满水识别-含数据集+pyqt界面

代码下载地址&#xff1a; https://download.csdn.net/download/qq_34904125/89374853 本代码是基于python pytorch环境安装的。 下载本代码后&#xff0c;有个requirement.txt文本&#xff0c;里面介绍了如何安装环境&#xff0c;环境需要自行配置。 或可直接参考下面博文…

花键轴类零件加工方法有哪些?

花键轴零件的加工方法 一辆普通中型卡车上约含 30 个花键轴零件, 通常用在离合器、变速器、传动轴总成、差速器、转向总成等位置。 花键轴零件的加工工艺是传统的切削加工和塑形成形加工两种。传统工艺如下的8个主要工序&#xff1a; 下料→锻造毛坯→毛坯加工→外花键加工…

kv视频如何转码mp4格式,kv转换mp4最简单方法

在数字化时代&#xff0c;视频格式转换成为了一项日常需求。有时候我们需要把kv格式转换为MP4格式。下面将详细介绍kv转MP4的方法 方法一、 1、使用 "小白兔视频格式在线转换网站" 2、地址发给"小白兔视频格式在线转换网站"的客服&#xff0c;客服下载即可…

Unity 从0开始编写一个技能编辑器_02_Buff系统的生命周期

工作也有一年了&#xff0c;对技能编辑器也有了一些自己的看法&#xff0c;从刚接触时的惊讶&#xff0c;到大量工作时觉得有一些设计的冗余&#xff0c;在到特殊需求的修改&#xff0c;运行效率低时的优化&#xff0c;技能编辑器在我眼中已经不再是神圣不可攀的存在的&#xf…