既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
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.概念:
消息队列:
顾名思义,消息队列就是一些消息的列表。用户可以在消息队列中添加消息和读取消息等。从这个观点上看,消息队列具有一定的FIFO特性,但是它可以实现消息的随机查询,比FIFO具有更大的优势。同时,这些消息又存在于内核中,由“队列ID”来标识。
#### 2.消息队列的实现步骤
消息队列的实现,包括创建或打开消息队列,添加消息,读取消息和控制消息队列这四种操作。
(1)其中创建或打开消息队列使用的函数是msgget(),这里创建的消息队列的数量会受到系统消息队列数量的限制。
(2)添加消息使用的函数是msgsnd(),它把消息添加到已经打开的消息队列的末尾;
(3)读取消息使用的函数是msgrcv(),它把消息从消息队列中取走,与FIFO不同的是,这里可以取走指定的某一条消息
(4)控制消息队列使用的函数时msgctl(),它可以完成更多项功能。
##### (1)msgget:
需要添加的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型:int msgget(key_t key, int msgflg);
函数参数:
key:消息队列的键值,多个进程可以通过它来访问同一个消息队列,其中有个特殊值 IPC_PRIVATE。它用于创建当前进程的私有消息队列。
msgflg:权限标志位
使用的是IPC_CREAT, 同共享内存
函数返回值:成功:消息队列ID
失败:-1
##### (2)msgsnd:
需要添加的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型:int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数参数:
msgid:消息队列的ID
msgp:指向消息结构的指针,该消息结构msgbuf通常为:
struct msgbuf
{
long mtype; /*消息类型,该结构必须从这个域开始*/
char mtext[L]; /*消息正文*/
}
msgsz:消息正文的字节数(不包括消息类型指针变量)
msgflag:
IPC_NOWAIT:若消息无法立即送达(比如:当前消息队列已满),函数会立即返回
0:msgsnd调用阻塞直到发送成功为止
函数返回值:成功:0
失败:-1
##### (3)msgrcv:
需要添加的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
函数参数:
msgid:消息队列的ID
msgp:指向消息结构的指针,该消息结构msgbuf通常为:
struct msgbuf
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
0:msgsnd调用阻塞直到发送成功为止
函数返回值:成功:0
失败:-1
##### (3)msgrcv:
需要添加的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数原型:ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
函数参数:
msgid:消息队列的ID
msgp:指向消息结构的指针,该消息结构msgbuf通常为:
struct msgbuf
收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-GE6lffbo-1715716570045)]
[外链图片转存中…(img-OiZJS9lZ-1715716570046)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人
都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!