VxWorks中的任务间通信(信号量、共享内存、消息队列、管道、信号、事件、套接字socket)_csdn vxworks中任务间通信(信号量(1)

void nodeAdd(int data) {
LIST_NODE *node;
if((node = (LIST_NODE *)malloc(sizeof(LIST_NODE))) != NULL) {
node ->data = data;
semTake(nodeListGuardSemId, WAIT_FOREVER);
node->pNextNode = pCurrNode;
pCurrNode = node;
semGive(nodeListGuardSemId);
}
else {
printf(“nodeAdd: out of Memory.\n”);
taskSuspend(0);
}

return;
}

/**************/
void schlep(void) {
int i;
while(1) {
for(i = 0; i < NUM_SAMPLE; i++) {
semTake(dataSemId,WAIT_FOREVER);
nodeAdd(cosmicData);
}

semGive(syncSemId);
}
return;
}

/*************/
void nodeScrap(void) {
LIST_NODE *pTmpNode;

semTake(nodeListGuardSemId, WAIT_FOREVER);
if(pCurrNode != NULL) {
pTmpNode = pCurrNode;
pCurrNode = pCurrNode->pNextNode;
free(pTmpNode);
}

semGive(nodeListGuardSemId);

return;
}

/*****************/
void crunch(void) {
int sampleSum;

while(1) {
sampleSum = 0;

semTake(syncSemId, WAIT_FOREVER);

semTake(nodeListGuardSemId, WAIT_FOREVER);

while(pCurrNode != NULL) {
sampleSum += pCurrNode->data;

nodeScrap();
}

semGive(nodeListGuardSemId);

result = sampleSum;
}
return;
}

/****************/
void monitor(void) {
BOOL isHot = FALSE;
BOOL averge = 0;

averge = RAND_MAX*NUM_SAMPLE/2;

while(1) {
if ((!isHot) && (result >= averge)) {
isHot = TRUE;
printf(“HOT\n”);
}
else if(isHot && (result < averge))
{
isHot = FALSE;
printf(“COOL\n”);
}
}

return;
}

/*****************/
void progStop(void) {
result = semTake(nodeListGuardSemId, WAIT_FOREVER);

if(result == OK) {
taskDelete(tidCosmos);
taskDelete(tidSchlep);
taskDelete(tidCrunch);
taskDelete(tidMonitor);

while(pCurrNode != NULL) {
nodeScrap();
}
}

semDelete(dataSemId);
semDelete(syncSemId);
semDelete(nodeListGuardSemId);

printf(“BYE!\n”);
return;
}

在这里插入图片描述

共享内存

VxWorks5.5中是没有进程线程一说的,都是以任务的形式存在,如果非要做个比较,那任务应该是和操作系统中线程的概念是一致的,可以大致认为VxWorks操作系统启动了一个主线程,然后在这个主线程中创建其他线程(任务)。

因此,VxWorks5.5中的任务运行于同一个线性地址空间,各个任务之间可以直接通过共享内存实现信息共享和信息传递。共享内存的存在形式可以是全局变量的简单变量,数组,链表,环形缓冲以及指针,他们可以在不同的任务上下文中访问,如下图所示

在这里插入图片描述

需要注意的是,任务之间如果通过共享内存的方式共享和传递信息,常常需要额外的保护措施,如信号量互斥,中断上锁,任务抢占上锁等,否则会产生访问共享内存这段代码的可重入性问题。

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723214909177.png
https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723214927817.png

消息队列

前面介绍的信号量可以实现同步和互斥机制,共享内存可以达到任务间的信息共享,但是都不能提供完善的响应式交互信息方式,VxWorks5.5提供了一种更为高级的机制,也是单CPU中VxWorks的任务间最主要的通信机制。

image-20210723215257430

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723215334895.png

在这里插入图片描述

代码实例:

给出一个两个任务间通过消息队列进行单向通信的简单例子,然后给出一个基于客服端/服务器架构的多个任务间通信的例子。

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723215747066.png

#include “vxWorks.h”
#include “msgQlib.h”

#define MAX_MSGS (10)
#define MAX_MSG_LEN (100)
#define STACK_SIZE (20000)
#define DELAY_TICKS (50)

int tidTask1;
int tidTask2;
MSG_Q_ID myMsgQId;

STATUS porgStart(void);
STATUS task1(void);
STATUS task2(void);
void progStop(void);

/**************/
STATUS progStart(void) {
myMsgQId = msgQCreate(MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY);
if(myMsgQId == NULL) {
return (ERROR);
}

tidTask1 = taskSpawn(“tTask1”, 200, 0, STACK_SIZE, (FUNCPTR)task1,0,0,0,0,0,0,0,0,0,0);
tidTask2 = taskSpawn(“tTask2”, 200, 0, STACK_SIZE, (FUNCPTR)task2,0,0,0,0,0,0,0,0,0,0);
return (OK);
}

/*************/
#define MESSAGE “Greetings from Task1”

STATUS task1(void) {
while(1) {
if(msgQSend(myMsgQId, MESSAGE, sizeof(MESSAGE), WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) {
return (ERROR);
}

taskDelay(DELAY_TICKS);
}
return (OK);
}

/***************/
STATUS task2(void) {
char msgBuf[MAX_MSG_LEN];

while(1) {
memset(msgBuf, 0, MAX_MSG_LEN);

if(msgQReceive(myMsgQId, msgBuf, MAX_MSG_LEN, WAIT_FOREVER) == ERROR) {
return (ERROR);
}

printf(“Message from task1: %s\n”,msgBuf);
}
return (OK);
}

/*****************/
void progStop(void) {
taskDelete(tidTask1);
taskDelete(tidTask2);

msgQDelete(myMsgQId);
printf(“BYE!\n”);

return;
}

在这里插入图片描述

基于客服端/服务器架构的多任务间通信

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723222424134.png
https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210723222435981.png

#include “vxWorks.h”
#include “msgQLib.h”

#define MAX_MSGS (10)
#define MAX_MSG_LEN sizeof(MESSAGE)
#define STACK_SIZE 20000
#define DELAY_TICKS 50
#define NUM_CLIENT 2

#define MID_CLIENT(id) (id)
#define MID_SERVER NUM_CLIENT

typedef struct _MESSAGE {
int mSendId;
int mRecvId;
int mData;
}MESSAGE;

int tidServer;
int tidClient[NUM_CLIENT];
MSG_Q_ID msgQIdServer;
MSG_Q_ID msgQIdClient[NUM_CLIENT];

STATUS progStart(void);
STATUS server(void);
STATUS client(int id);
void progStop(void);

STATUS progStart(void) {
int id;

msgQIdServer = msgQCreate(MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY);
if(msgQIdServer == NULL) {
return (ERROR);
}

for (id = 0; id < NUM_CLIENT; id++) {
msgQIdClient[id] = magQCreate(MAX_MSGS, MAX_MSG_LEN, MSG_Q_PRIORITY);

if(msgQIdClient[id] == NULL) {
return (ERROR);
}
}

tidServer = taskSpawn(“tServer”, 220, 0, STACK_SIZE, (FUNCPTR)server, 0,0,0,0,0,0,0,0,0,0);

for(id = 0; id < NUM_CLIENT; id++) {
char tempName[20];
sprintf(tempName, “tClient%d”, id);
tidClient[id] = taskSpawn(tempName, 200, 0, STACK_SIZE, (FUNCPTR)client, id,0,0,0,0,0,0,0,0,0,0);
}

return (OK);
}

STATUS server(void) {
MESSAGE rxMsg;
MESSAGE txMsg;

txMsg.mSendId = MID_SERVER;

while(1) {
if(msgQReceive(msgQIdServer, (char*)&rxMsg, MAX_MSG_LEN, WAIT_FOREVER) == ERROR) {
return (ERROR);
}

if (rxMsg.mRecvId != MID_SERVER) {
return (ERROR);
}

if((rxMsg.mSendId < MID_CLIENT(0)) || (rxMsg.mSendId > MID_CLIENT(NUM_CLIENT - 1))) {
return (ERROR);
}

printf(“\nServer: receive a data %d from tClient %d\n”, rxMsg.mData, rxMsg.mSendId);

txMsg.mRecvId = rxMsg.mSendId;
txMsg.mData = rxMsg.mData;

if(msgQSend(msgQIdClient[rxMsg.mSendId], (char*)&txMsg, sizeof(MESSAGE), WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) {
return (ERROR);
}
}

return (OK);
}

STATUS client(int id) {
MESSAGE rxMsg;
MESSAGE txMsg;

txMsg.mSendId = MID_CLIENT(id);
txMsg.mRecvId = MID_SERVER;

while(1) {
txMsg.mData = rand();

if(msgQSend(msgQIdServer, (char*)&txMsg, sizeof(MESSAGE), WAIT_FOREVER, MSG_PRI_NORMAL) == ERROR) {
return (ERROR);
}

printf(“\nClient%d: transmit a data %d to tServer\n”, id, txMsg.mData);

if(msgQReceive(msgQIdClient[id], (char*)&rxMsg, MAX_MSG_LEN, 20) == ERROR) {
printf(“\ntClient %d: wait ACK timeout!!!\n”);
continue;
}

printf(“\ntClient %d: receive the ACK from tServer”, id);
if(txMsg.mData == rxMsg.mData) {
printf(“, and data check OK!\n”);
}
else {
printf(“\n, but data check ERROR!!!\n”);
printf(“tx data(%d) != ACK data(%d)\n”, txMsg.mData, rxMsg.mData);
}

taskDelay(DELAY_TICKS + (txMsg .mData % DELAY_TICKS));
}

return (OK);
}

/********************/
void progStop(void) {
int id;

for(id = 0; id < NUM_CLIENT; id++) {
taskDelete(tidClient[id]);
}

taskDelete(tidServer);

msgQDelete(msgQIdServer);
for(id = 0; id < NUM_CLIENT; id++) {
msgQDelete(msgQIdClient[id]);
}

printf(“BYE!\n”);

return;
}

管道

VxWorks5.5提供的管道机制与消息队列比较类似,创建管道时也会分配一个消息队列,不同的是,管道作为一种虚拟I/O设备,它可由VxWorks5.5提供的一套标准I/O接口来驱动、管理。

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210724001523968.png
https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210724001547935.png

管道代码实践

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210724001718277.png

#include “vxWorks.h”
#include “ioLib.h”
#include “pipeDrv.h”

#define MESSAGE “Greetings from Task 1”
#define MAX_MSGS (10)
#define MAX_MSG_LEN sizeof(MESSAGE)
#define STACK_SIZE 20000
#define DELAY_TICKS 50

int tidTask1;
int tidTask2;
int demoPipeFd;

STATUS porgStart(void);
STATUS task1(void);
STATUS task2(void);
void progStop(void);

STATUS progStart(void) {
int result;

result = pipeDevCreate(“/pipe/demo”, MAX_MSGS, MAX_MSG_LEN);
if(result == ERROR) {
return (ERROR);
}

demoPipeFd = open(“/pipe/demo”, O_RDWR, 0);
if(demoPipeFd == ERROR) {
return (ERROR);
}

tidTask1 = taskSpawn(“tTask1”, 200, 0, STACK_SIZE, (FUNCPTR)task1, 0,0,0,0,0,0,0,0,0,0);
tidTask2 = taskSpawn(“tTask2”, 200, 0, STACK_SIZE, (FUNCPTR)task2, 0,0,0,0,0,0,0,0,0,0);

return (OK);
}

STATUS task1(void) {
while(1) {
write(demoPipeFd, MESSAGE, sizeof(MESSAGE));
taskDelay(DELAY_TICKS);
}
return (OK);
}

STATUS task2(void) {
char msgBuf[MAX_MSG_LEN];
int len = 0;
int result;
fd_set readFd;

while(1) {
memset(msgBuf, 0, MAX_MSG_LEN);
len = 0;

while(len < sizeof(MESSAGE)) {
FD_ZERO(&readFd);
FD_SET(demoPipeFd, &readFd);
result = select(sizeof(fd_set), &readFd, NULL, NULL,NULL);
if(result == 0) {
return (ERROR);
}

len += read(demoPipeFd, msgBuf, sizeof(MESSAGE) - len);
}

printf(“Message from task1: %s\n”, msgBuf);
}
return (OK);
}

void progStop(void) {
taskDelete(tidTask1);
taskDelete(tidTask2);

close(demoPipeFd);
pipeDevDelete(“/pipe/demo”, TRUE);

printf(“BYE!\n”);
return;
}

image-20210724003923016

信号

信号是一种由事件触发的软件中断,它可以异步地改变信号接收任务的执行流程,使其转向执行对应的信号处理程序,所谓软件中断是指,其触发事件来自系统内部执行的软件,而不像通常的中断那样,由CPU的外部管脚接收到的中断信号触发。

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210724004515183.png

https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210724005840224.png

在这里插入图片描述

#include <stdio.h>
#include “vxWorks.h”
#include “semLib.h”
#include “errno.h”
#include “sigLib.h”

#define STACK_SIZE 20000

SEM_ID semId;
int tidSigReceiver;

STATUS sigReceiver(void);
STATUS txSignal(void);
STATUS sigHandler(int sig);

STATUS progStart(void) {

semId = semBCreate(SEM_Q_FIFO, SEM_EMPTY);

tidSigReceiver = taskSpawn(“tSigReceiver”, 200, 0, STACK_SIZE, (FUNCPTR)sigReceiver,0,0,0,0,0,0,0,0,0,0);

printf(“\nRun cmd “txSignal()” in shell to send a signal.\n”);
return (OK);
}

STATUS sigReceiver(void) {
signal(SIGUSR1, sigHandler);

semTake(semId, WAIT_FOREVER);

return (OK);
}

STATUS sigHandler(int sig) {
if(sig != SIGUSR1) {
logMsg(“\nsigHandler: Invalid sig %d\n”, sig, 0, 0, 0, 0, 0);
return;
}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-Sl5eLOMj-1712918800171)]
[外链图片转存中…(img-iJZYQUzS-1712918800172)]
[外链图片转存中…(img-4m3M8plI-1712918800173)]
[外链图片转存中…(img-5CXwa3as-1712918800173)]
[外链图片转存中…(img-Hq8UeTIK-1712918800174)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-osvLeply-1712918800174)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值