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中的任务运行于同一个线性地址空间,各个任务之间可以直接通过共享内存实现信息共享和信息传递。共享内存的存在形式可以是全局变量的简单变量,数组,链表,环形缓冲以及指针,他们可以在不同的任务上下文中访问,如下图所示
需要注意的是,任务之间如果通过共享内存的方式共享和传递信息,常常需要额外的保护措施,如信号量互斥,中断上锁,任务抢占上锁等,否则会产生访问共享内存这段代码的可重入性问题。
消息队列
前面介绍的信号量可以实现同步和互斥机制,共享内存可以达到任务间的信息共享,但是都不能提供完善的响应式交互信息方式,VxWorks5.5提供了一种更为高级的机制,也是单CPU中VxWorks的任务间最主要的通信机制。
代码实例:
给出一个两个任务间通过消息队列进行单向通信的简单例子,然后给出一个基于客服端/服务器架构的多个任务间通信的例子。
#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;
}
基于客服端/服务器架构的多任务间通信
#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接口来驱动、管理。
管道代码实践
#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;
}
信号
信号是一种由事件触发的软件中断,它可以异步地改变信号接收任务的执行流程,使其转向执行对应的信号处理程序,所谓软件中断是指,其触发事件来自系统内部执行的软件,而不像通常的中断那样,由CPU的外部管脚接收到的中断信号触发。
#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语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远。不论你是正从事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行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!