嵌入式学习DAY27 --- System V 共享内存 ,POSIX 信号量 ,POSIX 消息队列_posix 共享内存 嵌入式平台

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

函数功能:获得共享内存
函数参数: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);

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

nt 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);

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-0Ba9Rymf-1715716610756)]
[外链图片转存中…(img-Zy9qL7hQ-1715716610756)]

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值