嵌入式入门学习笔记,遇到的问题以及心得体会!
DAY27
概述:
一、System V 共享内存
二、POSIX 信号量
三、POSIX 消息队列
笔记:
注意:
不论是怎样的通信,只要牵扯公共资源
读读不互斥
读写互斥
写写互斥
一、System V 共享内存
1.概念:
可以说,共享内存是一种最为高效的进程间通信方式。因为,进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换信息。内核专门流出了一块内存。这段内存可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不要进行数据的复制,从而大大提高了效率。当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。
2.实现过程:
共享内存的实现分为两个步骤:
(1)创建共享内存,这里用到的函数时shmget(),也就是从内存种获得一段共享内存区域。
(2)映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,这里使用的函数时shmat()。到这里就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O读写命令对其进行操作。
(3)撤销映射,使用shmdt()函数。
3.所用函数:
(1)ftok函数:
#include <sys/types.h>
#include <sys/ipc.h>
/\*
\*函数名:ftok
\*函数功能:convert a pathname and a project identifier to a
\* System V IPC key, Key可用于msgget, semget, or
\* shmget的key参数
\*函数参数:
\* const char \*pathname:想要输出的字符串的首地址
\* int proj\_id:一个整型标识
\*函数返回值:key\_t:成功返回一个key\_t的key,失败返回-1
\*/
key_t ftok(const char \*pathname, int proj_id);
(2)shmget函数:
#include <sys/ipc.h>
#include <sys/shm.h>
/\*
函数名:shmget
函数功能:获得共享内存
函数参数:key:共享内存的键值,多个进程可以通过它访问同一个共享内存。其中有个特殊值 IPC\_PRIVATE,用于创建当前进程的私有共享内存。
size:共享内存的大小
shmflg:同open()函数的权限位,也可以使用八进制表示法
函数返回值:
成功:共享内存段标识符
失败:-1
\*/
int shmget(key_t key, size_t size, int shmflg);
(3)shmat函数:
#include <sys/types.h>
#include <sys/shm.h>
函数参数:
shmid:要映射的共享内存区标识符。
shmaddr:将共享内存映射到指定地址若为NULL,则表示系统自动分配地址,并把该段共享 内存映射到调用进程的地址空间)
shmflg:SHM_RDONLY:共享内存只读
默认0:共享内存可读可写
函数返回值:成功:被映射的段地址
出错:-1
void \*shmat(int shmid, const void \*shmaddr, int shmflg);
(4)shmdt函数:
#include <sys/types.h>
#include <sys/shm.h>
函数原型:int shmdt(const void \*shmaddr);
函数参数:shmaddr:被映射的共享内存段地址
函数返回值:
成功:0
失败:-1
4.如何查看共享内存:
ipcs -m
5.如何删除共享内存:
ipcrm -m [shmid]
6.代码演示
1.read_p ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
typedef struct msgbuf {
long mtype; /\* message type, must be > 0 \*/
char mtext[50]; /\* message data \*/
}Msg_Buf;
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'a');
if(key < 0)
{
puts("ftok error.");
return -1;
}
//msgget
int msgqid = -1;
msgqid = msgget(key, IPC_CREAT | 0664);
if(msgqid < 0)
{
puts("msgget error.");
return -1;
}
while(1)
{
puts("recv message from queue:");
//msgsnd
Msg_Buf msg;
memset(msg.mtext, 0, 50);
msg.mtype = getpid();
int ret = msgrcv(msgqid, &msg, 50, 0, 0);
if(ret > 0)
{
puts(msg.mtext);
}
else
{
break;
}
if(strncmp(msg.mtext,"quit",4) == 0)
{
break;
}
}
msgctl(msgqid,IPC_RMID,NULL);
return 0;
}
2.write_p ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
typedef struct msgbuf {
long mtype; /\* message type, must be > 0 \*/
char mtext[50]; /\* message data \*/
}Msg_Buf;
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'a');
if(key < 0)
{
puts("ftok error.");
return -1;
}
//msgget
int msgqid = -1;
msgqid = msgget(key, IPC_CREAT | 0664);
if(msgqid < 0)
{
puts("msgget error.");
return -1;
}
while(1)
{
puts("input some message send to queue:");
//msgsnd
Msg_Buf msg;
char \*p = fgets(msg.mtext, 50, stdin);
if(NULL == p)
{
puts("get msg.text error.");
continue;
}
msg.mtype = getpid();
int ret = msgsnd(msgqid, &msg, 50, 0);
if(ret < 0)
{
puts("msgsnd error.");
continue;
}
if(strncmp(msg.mtext,"quit",4) == 0)
{
break;
}
}
return 0;
}
二、POSIX 信号量
1.需求:
7个进程实现一个餐厅的流水线
买菜—>洗菜—>切菜---->炒菜---->装盘—>吃—>洗盘
7个进程之间有顺序关系
如何保证7个进程对菜操作权限和顺序
2.信号量概述:
(1)在多任务操作系统中,多个进程/线程会同时运行。多个任务可能为了完成同一个事情而相互协作,这样就形成了任务之间的同步关系。同样,不同任务之间为了争夺有限的系统资源(硬件或软件资源)会进入竞争状态,这样就是任务之间的互斥关系。
(2)任务之间的互斥与同步关系存在的根源在于临界资源。临界资源是指在同一个时刻只允许有限个(通常只有一个)任务可以访问(读)或者修改(写)的资源。通常包括硬件资源(处理器、内存、存储器以及其他外围设备等)和软件资源(共享代码段、共享结构体和变量)。访问临界资源的代码称为临界区。
(3)信号量是用来解决进程/线程之间的同步与互斥问题的一种通信机制,包括一个称为信号量的变量和在该信号量下等待资源的进程等待队列,以及对信号量进行的两个原子操作(PV操作)。其中,信号量对应于某一种资源,取一个非负的整数值。信号量值指的是当前可用的该资源的数量,若它等于0则意味着目前没有可用的资源。
3.PV原子操作的具体定义:
(1)P操作:
如果有可用的资源(信号量的值大于0),则占用一个资源(信号量值减1,进入临界区代码);如果没 有可用的资源(信号量值等于0),则被阻塞,直到系统将资源分配给该任务(进入等待队列,一直 等到有资源的时候被唤醒)。
(2)V操作:
如果该信号量的等待队列中有任务在等待资源,则唤醒一个阻塞任务,如果没有任务等待它,则 释放一个资源(信号量值加1)
注意:
最简单的信号量只有0和1两种值,这两种信号量被称为二值信号量。在本节中,主要讨论二值信号量。二值信号量的应用比较容易扩展到使用多值信号量的情况。
4.信号量编程:
步骤:
Linux下,使用有名信号量通常分为以下几个步骤:
(1)创建信号量或获得系统已经存在的有名信号量,此时需要调用sem_open()函数,不同的进程通过使用同一个信号量键值来获得同一个信号量。并初始化信号量的值。
(2)获取信号量的值,此时使用sem_getvalue()。
(3)信号量减一,使用sem_wait()。
(4)信号量加一,使用sem_post()。
(5)关闭信号量,使用sem_close()。
(1)sem_open:
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
sem_t \*sem\_open(const char \*pathname, int oflag);
/\*
\*函数名:sem\_open
\*函数功能:打开一个信号量,如果信号量不存在,则创建信号量
\*函数参数:
\* const char \*pathname:信号量的名字(标识)
\* int oflag:同文件IO的创建时的权限
\* O\_CREAT | O\_RDWR
\* mode\_t mode:同文件权限
\* unsigned in value:信号量的初始值
\*函数返回值:sem\_t \*:成功返回信号量操作对象的指针
\*/
sem_t \*sem\_open(const char \*pathname, int oflag, mode_t mode, unsigned int value);
(2)sem_getvalue:
#include <semaphore.h>
/\*
\*函数名:sem\_getvalue
\*函数功能:获取当前信号量的值
\*函数参数:
\* sem\_t \*sem:信号量的操作指针
\* int \*sval:存储信号量值得内存首地址
\*函数返回值:int:成功返回0,失败返回-1
\*/
int sem\_getvalue(sem_t \*sem, int \*sval);
(3)sem_wait:
#include <semaphore.h>
/\*
\*函数名:sem\_wait
\*函数功能:信号量值减一
\*函数参数:sem\_t \*sem:信号量的操作指针
\*函数返回值:int:成功返回0,失败返回-1
\*/
int sem\_wait(sem_t \*sem);
(4)sem_post:
#include <semaphore.h>
/\*
\*函数名:sem\_post
\*函数功能:信号量值加一
\*函数参数:sem\_t \*sem:信号量的操作指针
\*函数返回值:int:成功返回0,失败返回-1
\*/
int sem\_post(sem_t \*sem);
(5)sem_close:
#include <semaphore.h>
/\*
\*函数名:sem\_close
\*函数功能:关闭一个有名信号量
\*函数参数:sem\_t \*sem:信号量的操作指针
\*函数返回值:int:成功返回0,失败返回-1
\*/
int sem\_close(sem_t \*sem);
注意:
进程中使用的信号量,称之为有名信号量
编译时链接库 -lpthread
5.代码演示:
代码中以4个进程来代替前面需求中说的7个进程,进行简单的演示:
1.p1.c ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include <fcntl.h> /\* For O\_\* constants \*/
#include <sys/stat.h> /\* For mode constants \*/
#include <semaphore.h>
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'c');
if(key < 0)
{
puts("ftok error.");
return -1;
}
char buf[30];
//shmget
int shmid = shmget(key,sizeof(buf),IPC_CREAT | 0664);
if(shmid < 0)
{
puts("shmget error.");
return 0;
}
//shmat
char \*shmaddr = NULL;
shmaddr = (char \*)shmat(shmid, NULL, 0);
sem_t \*mysem = NULL;
mysem = sem\_open("mysem", O_CREAT | O_RDWR, 0664, 6);
if(NULL == mysem)
{
puts("sem\_open error.");
shmdt(shmaddr);
return -1;
}
while(1)
{
int sem_v = 0;
sem\_getvalue(mysem, &sem_v);
printf("sem\_v:%d\n",sem_v);
if(sem_v == 6)
{
sem\_wait(mysem);
puts(shmaddr);
sprintf(buf,"buy v");
memset(shmaddr,0,sizeof(buf));
memcpy(shmaddr,buf,strlen(buf));
}
sleep(3);
}
//shmdt
shmdt(shmaddr);
sem\_close(mysem);
return 0;
}
2.p2.c ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include <fcntl.h> /\* For O\_\* constants \*/
#include <sys/stat.h> /\* For mode constants \*/
#include <semaphore.h>
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'c');
if(key < 0)
{
puts("ftok error.");
return -1;
}
char buf[30];
//shmget
int shmid = shmget(key,sizeof(buf),IPC_CREAT | 0664);
if(shmid < 0)
{
puts("shmget error.");
return 0;
}
//shmat
char \*shmaddr = NULL;
shmaddr = (char \*)shmat(shmid, NULL, 0);
sem_t \*mysem = NULL;
mysem = sem\_open("mysem", O_CREAT | O_RDWR, 0664, 6);
if(NULL == mysem)
{
puts("sem\_open error.");
shmdt(shmaddr);
return -1;
}
while(1)
{
int sem_v = 0;
sem\_getvalue(mysem, &sem_v);
printf("sem\_v:%d\n",sem_v);
if(sem_v == 5)
{
sem\_wait(mysem);
puts(shmaddr);
sprintf(buf,"brush v");
memset(shmaddr,0,sizeof(buf));
memcpy(shmaddr,buf,strlen(buf));
}
sleep(3);
}
//shmdt
shmdt(shmaddr);
sem\_close(mysem);
return 0;
}
3.p3.c ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include <fcntl.h> /\* For O\_\* constants \*/
#include <sys/stat.h> /\* For mode constants \*/
#include <semaphore.h>
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'c');
if(key < 0)
{
puts("ftok error.");
return -1;
}
char buf[30];
//shmget
int shmid = shmget(key,sizeof(buf),IPC_CREAT | 0664);
if(shmid < 0)
{
puts("shmget error.");
return 0;
}
//shmat
char \*shmaddr = NULL;
shmaddr = (char \*)shmat(shmid, NULL, 0);
sem_t \*mysem = NULL;
mysem = sem\_open("mysem", O_CREAT | O_RDWR, 0664, 6);
if(NULL == mysem)
{
puts("sem\_open error.");
shmdt(shmaddr);
return -1;
}
while(1)
{
int sem_v = 0;
sem\_getvalue(mysem, &sem_v);
printf("sem\_v:%d\n",sem_v);
if(sem_v == 4)
{
sem\_wait(mysem);
puts(shmaddr);
sprintf(buf,"cut v");
memset(shmaddr,0,sizeof(buf));
memcpy(shmaddr,buf,strlen(buf));
}
sleep(3);
}
//shmdt
shmdt(shmaddr);
sem\_close(mysem);
return 0;
}
4.p4.c ---------------------------------------------------------------------------------------如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
#include <string.h>
#include <sys/shm.h>
#include <fcntl.h> /\* For O\_\* constants \*/
#include <sys/stat.h> /\* For mode constants \*/
#include <semaphore.h>
int main()
{
//ftok
key_t key = -1;
key = ftok(".",'c');
if(key < 0)
{
puts("ftok error.");
return -1;
}
char buf[30];
//shmget
int shmid = shmget(key,sizeof(buf),IPC_CREAT | 0664);
if(shmid < 0)
{
puts("shmget error.");
return 0;
}
//shmat
char \*shmaddr = NULL;
shmaddr = (char \*)shmat(shmid, NULL, 0);
sem_t \*mysem = NULL;
mysem = sem\_open("mysem", O_CREAT | O_RDWR, 0664, 6);
if(NULL == mysem)
{
puts("sem\_open error.");
shmdt(shmaddr);
return -1;
}
while(1)
{
int sem_v = 0;
sem\_getvalue(mysem, &sem_v);
printf("sem\_v:%d\n",sem_v);
if(sem_v == 3)
{
sem\_wait(mysem);
puts(shmaddr);
sprintf(buf,"do v");
memset(shmaddr,0,sizeof(buf));
memcpy(shmaddr,buf,strlen(buf));
sem\_post(mysem);
sem\_post(mysem);
sem\_post(mysem);
sem\_post(mysem);
}
sleep(3);
}
//shmdt
shmdt(shmaddr);
sem\_close(mysem);
return 0;
}
三、System V消息队列:
1.概念:
还有兄弟不知道网络安全面试可以提前刷题吗?费时一周整理的160+网络安全面试题,金九银十,做网络安全面试里的显眼包!
王岚嵚工程师面试题(附答案),只能帮兄弟们到这儿了!如果你能答对70%,找一个安全工作,问题不大。
对于有1-3年工作经验,想要跳槽的朋友来说,也是很好的温习资料!
【完整版领取方式在文末!!】
93道网络安全面试题
内容实在太多,不一一截图了
黑客学习资源推荐
最后给大家分享一份全套的网络安全学习资料,给那些想学习 网络安全的小伙伴们一点帮助!
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
😝朋友们如果有需要的话,可以联系领取~
1️⃣零基础入门
① 学习路线
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
② 路线对应学习视频
同时每个成长路线对应的板块都有配套的视频提供:
2️⃣视频配套工具&国内外网安书籍、文档
① 工具
② 视频
③ 书籍
资源较为敏感,未展示全面,需要的最下面获取
② 简历模板
因篇幅有限,资料较为敏感仅展示部分资料,添加上方即可获取👆
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!