基于嵌入式操作系统VxWorks的多任务并发程序设计(4)――任务间通信B

简介:
管道可以看作受驱动器 pipeDrv 管理的虚拟 I/O 设备,使用基本的 I/O 系统接口可以读、写和操作管道,这些函数包括 read write open close ioctl select 等。与 pipe 密切相关的其它 API 还有:
1 pipeDrv( ) :初始化 pipeDrv ,函数原型:
STATUS pipeDrv (void);
2 pipeDevCreate( ) :创建 pipe ,函数原型:
STATUS pipeDevCreate
    (
    char * name,              /*  创建的 pipe  */
    int    nMessages,         /* pipe 中的最大消息数  */
    int    nBytes             /*  每个消息的大小  */
    );
3 pipeDevDelete :删除 pipe ,函数原型:
STATUS pipeDevDelete
    (
    char * name,              /*  要删除的 pipe  */
    BOOL   force              /*  如果为真,则强制删除 pipe */
    );
下面我们看看 pipe 使用的 demo
3 :管道
/* includes */
#include "vxWorks.h"
#include "taskLib.h"
#include "stdio.h"
#include "ioLib.h"
#include "pipeDrv.h"
 
/*globals */
typedef struct
{
  VOIDFUNCPTR routine;   /*  函数指针  */
  int arg;
} MSG_REQUEST; /* message structure */
 
#define TASK_PRI          254             /* tServers task's priority */
#define TASK_STACK_SIZE  5000      /* tServer task's stack size */
#define PIPE_NAME       "/pipe/server"  /* name of the pipe device */
#define NUM_MSGS  10     /* max number of messages in the pipe */
 
LOCAL int pipeFd; /* File descriptor for the pipe device */
LOCAL void pipeServer(); /* server task */
 
/* serverStart :初始化 pipeServer 任务以执行管道中夹带的函数  */
STATUS serverStart()
{
  if (pipeDevCreate(PIPE_NAME, NUM_MSGS, sizeof(MSG_REQUEST)) == ERROR)
  {
    perror("Error in creating pipe"); /* print error if pipe is already
     * created, but do not return */
  }
 
  /* Open the pipe */
  if ((pipeFd = open(PIPE_NAME, UPDATE, 0)) == ERROR)
  {
    perror("Error in opening pipe device");
    return (ERROR);
  }
 
  /* Spawn the server task */
  if (taskSpawn("tServer", TASK_PRI, 0, TASK_STACK_SIZE, (FUNCPTR)pipeServer, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
  {
    perror("Error in spawning tServer task");
    close(pipeFd);
    return (ERROR);
  }
 
  return (OK);
}
 
/* serverSend  :发送管道消息,将函数指针作为消息的一部分  */
STATUS serverSend(VOIDFUNCPTR routine, /* name of the routine to execute */ int arg /* argument of the routine */
)
{
  MSG_REQUEST msgRequest;
  int status;
 
  /* Initialize the message structure */
  msgRequest.routine = routine;
  msgRequest.arg = arg;
 
  /* Send the message and return the results */
  status = write(pipeFd, (char*) &msgRequest, sizeof(MSG_REQUEST));
 
  return ((status == sizeof(MSG_REQUEST)) ? OK : ERROR);
}
 
/* pipeServer :读取管道消息并执行管道消息中夹带的函数  */
LOCAL void pipeServer()
{
  MSG_REQUEST msgRequest;
 
  while (read(pipeFd, (char*) &msgRequest, sizeof(MSG_REQUEST)) > 0)
    (*msgRequest.routine)(msgRequest.arg);
}
    上述程序中, pipeServer 执行于非常低的优先级 (254 ) ,当我们在 shell 中输入“ serverSend(VOIDFUNCPTR routine, int arg)   时, pipeServer 将读到管道中的消息,并执行“ *routine (arg) ”。
        为对此进行验证,我们在程序中再添加一个函数:
void PRINT(int arg)
{
       printf("%d",arg);
}
当我们在 tShell 中输入“ serverSend(PRINT,2); ”,在 VxSim 中将输出 2

9.套接字

不论网络中的节点使用什么操作系统,套接字的通信都是完全对等的。套接字有两种:
1 )流套接字( SOCK_STREAM ,采用 TCP 协议):流套接字提供了双向的、有序的、无重复并且无记录边界的数据流服务;
2 )数据报套接字( SOCK_DGRAM ,采用 UDP 协议):数据报套接字也支持双向数据传输,但并不保证是可靠、有序和无重复的。
另外还有一种 RAW 套接字,但不常见。
VxWorks 中与 Socket 相关的函数有:
1 socket() :创建套接字     ,原型为:
int socket
    (
    int domain,    /* address family (for example, AF_INET) */
    int type,      /* SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW */
    int protocol   /* socket protocol (usually 0) */
    );
2 bind() :给套接字绑定名称   ,原型为:
STATUS bind
    (
    int               s,      /* socket descriptor */
    struct sockaddr * name,   /* name to be bound */
    int            namelen /* length of name */
    );
3 listen() :服务端监听 TCP 连接请求,原型为:
STATUS listen
    (
    int s,                    /* socket descriptor */
    int backlog               /* number of connections to queue */
    );
4 accept() :服务端接受 TCP 连接请求,原型为:
int accept
    (
    int            s,      /* socket descriptor */
    struct sockaddr * addr,   /* peer address */
    int *           addrlen /* peer address length */
    );
5 connect() :客户端请求连接套接字,原型为:
STATUS connect
    (
    int               s,      /* socket descriptor */
    struct sockaddr * name,   /* addr of socket to connect */
    int            namelen /* length of name, in bytes */
    );
6 shutdown() :关闭套接字间连接,原型为:
STATUS shutdown
    (
    int s,                /* socket to shut down */
    int how              /* 0:receives disallowed;1:sends disallowed;
2:sends and receives disallowed */
    );
7 sendto() send() sendmsg() :发送数据
int sendto
    (
    int               s,      /* socket to send data to */
    caddr_t           buf,    /* pointer to data buffer */
    int               bufLen, /* length of buffer */
    int               flags,  /* flags to underlying protocols */
    struct sockaddr * to,     /* recipient's address */
    int               tolen   /* length of to sockaddr */
    );
 
int send
    (
    int          s,           /* socket to send to */
    const char * buf,         /* pointer to buffer to transmit */
    int          bufLen,      /* length of buffer */
    int          flags        /* flags to underlying protocols */
    );
 
int sendmsg
    (
    int             sd,       /* socket to send to */
    struct msghdr * mp,       /* scatter-gather message header */
    int             flags     /* flags to underlying protocols */
    );
8 recvfrom () recv () recvmsg () :接收数据
int recvfrom
    (
    int               s,       /* socket to receive from */
    char *            buf,     /* pointer to data buffer */
    int               bufLen,  /* length of buffer */
    int               flags,   /* flags to underlying protocols */
    struct sockaddr * from,    /* where to copy sender's addr */
    int *             pFromLen /* value/result length of from */
    );
 
int recv
    (
    int    s,                 /* socket to receive data from */
    char * buf,               /* buffer to write data to */
    int    bufLen,            /* length of buffer */
    int    flags              /* flags to underlying protocols */
    );
 
int recvmsg
    (
    int             sd,       /* socket to receive from */
    struct msghdr * mp,       /* scatter-gather message header */
    int             flags     /* flags to underlying protocols */
    );
限于篇幅的关系,我们在此不在列举 socket 通信的例子。但在最后一次连载的综合实例中,将包括完整的 socket 通信过程源代码。

10.信号与异常处理

信号是 VxWorks 中用于异常处理的方式,信号的驱动和执行机制有点类似于硬件中断(可以认为是一种软件上的通告,即 software notification)。信号的生存期为从“产生”到“传递”,一个“产生”而未“传递”的信号处于 pending 状态。信号适宜进行异常处理,任务间的通信不要使用信号。
下面是从 Embry-Riddle Real-Time Laboratory 试验课程中获得的一个 signal 的例子:
4 :信号与异常处理
/* includes */
#include "vxWorks.h"
#include "sigLib.h"
#include "taskLib.h"
#include "stdio.h"
 
/* function prototypes */
void catchSIGINT(int);
void sigCatcher(void);
 
/* globals */
#define NO_OPTIONS 0
#define ITER1 100
#define LONG_TIME 1000000
#define HIGHPRIORITY 100
#define LOWPRIORITY 101
int ownId;
 
void sigGenerator(void) /* task to generate the SIGINT signal */
{
  int i, j, taskId;
  STATUS taskAlive;
 
  if ((taskId = taskSpawn("signal", 100, 0x100, 20000, (FUNCPTR)sigCatcher, 0,    0, 0, 0, 0, 0, 0, 0, 0, 0)) == ERROR)
    printf("taskSpawn sigCatcher failed\n");
 
  ownId = taskIdSelf(); /* get sigGenerator's task id */
 
  taskDelay(30); /* allow time to get sigCatcher to run */
 
  for (i = 0; i < ITER1; i++)
  {
    if ((taskAlive = taskIdVerify(taskId)) == OK)
    {
      printf("+++++++++++++++++++++++++++++++SIGINT sinal generated\n");
      kill(taskId, SIGINT); /* generate signal */
      /* lower sigGenerator priority to allow sigCatcher to run */
      taskPrioritySet(ownId, LOWPRIORITY);
    }
    else
     /* sigCatcher is dead */
      break;
  }
  printf("\n***************sigGenerator Exited***************\n");
}
 
void sigCatcher(void) /* task to handle the SIGINT signal */
{
  struct sigaction newAction;
  int i, j;
 
  newAction.sa_handler = catchSIGINT; /* set the new handler */
  sigemptyset(&newAction.sa_mask); /* no other signals blocked */
  newAction.sa_flags = NO_OPTIONS; /* no special options */
 
  if (sigaction(SIGINT, &newAction, NULL) ==  - 1)
    printf("Could not install signal handler\n");
 
  for (i = 0; i < ITER1; i++)
  {
    for (j = 0; j < LONG_TIME; j++)
      ;
    printf("Normal processing in sigCatcher\n");
  }
 
  printf("\n+++++++++++++++sigCatcher Exited+++++++++++++++\n");
}
 
void catchSIGINT(int signal) /* signal handler code */
{
  printf("-------------------------------SIGINT signal caught\n");
  /* increase sigGenerator priority to allow sigGenerator to run */
  taskPrioritySet(ownId, HIGHPRIORITY);
}
分析以上程序, kill() 函数产生信号,其原型为:
int kill
    (
    int tid,                  /* task to send signal to */
    int signo                 /* signal to send to task */
    );
sigaction() 函数将信号与信号处理函数进行绑定,一个信号处理函数类似于程序中的 catchSIGINT 函数,一般结构为:
void sigHandlerFunction(int signalNumber)
{
... /* signal handler code */
}
sigaction() 函数的原型为:
int sigaction
    (
    int               signo, /* signal of handler of interest */
    const struct sigaction * pAct,  /* location of new handler */
    struct sigaction *   pOact  /* location to store old handler */
    );
 signo 为信号序号,而输入参数 pAct 中存放的是信号处理函数的信息, pOact 是一个输出参数,可以获得老的信号处理函数信息。
运行上述程序,输出结果为:
Normal processing in sigCatcher 
     // 大量的 Normal processing in sigCatcher
Normal processing in sigCatcher 
+++++++++++++++sigCatcher Exited+++++++++++++++

我们将从下一次连载――《VxWorks中断处理》中发现中断与信号的相似性。




  本文转自 21cnbao 51CTO博客,原文链接:http://blog.51cto.com/21cnbao/120323,如需转载请自行联系原作者


相关文章
|
1月前
|
安全 Unix Linux
Unix是一个多用户、多任务的操作系统
Unix是一个多用户、多任务的操作系统
86 3
|
18天前
|
存储 iOS开发 MacOS
MacOS环境-手写操作系统-33-多任务多窗口
MacOS环境-手写操作系统-33-多任务多窗口
16 0
|
1月前
|
Web App开发 Linux iOS开发
操作系统的演变:从单任务到多核并发
在数字时代的浪潮中,操作系统作为计算机硬件与应用程序之间的桥梁,其发展历史充满了创新与变革。本文将带领读者穿越时空,探索操作系统如何从简单的单任务处理演化为今天能够高效管理多核处理器的复杂系统。我们将一窥各个时代下操作系统的设计哲学,以及它们是如何影响现代计算的方方面面。加入我们的旅程,一起见证技术的力量如何在每次迭代中重塑世界。
37 7
|
1月前
|
机器学习/深度学习 人工智能 算法
操作系统的未来:从多任务到深度学习的演变之路
本文将探讨操作系统如何从处理简单多任务发展到支持复杂的深度学习任务。我们将分析现代操作系统面临的新挑战,以及它们如何适应人工智能和大数据时代的要求。文章不仅回顾过去,也展望未来,思考操作系统在技术演进中的角色和方向。
48 3
|
1月前
|
人工智能 算法 数据挖掘
操作系统的演变:从单任务到多任务的旅程
操作系统(OS)是计算机系统的核心,它管理硬件资源、提供用户界面并运行应用程序。本文将探讨操作系统如何从单任务环境演变为支持多任务的环境,包括这一过程中的技术挑战和解决方案。我们将看到,随着计算需求的增长,操作系统必须适应更复杂的任务管理和资源分配策略,以提高效率和用户体验。通过这个旅程,我们不仅能够理解操作系统的发展,还能洞察未来可能的趋势。
47 5
|
2月前
|
机器学习/深度学习 人工智能 安全
操作系统的未来:从多任务处理到人工智能
【8月更文挑战第23天】本文将探讨操作系统的发展历程及其未来趋势,特别是人工智能在操作系统中的应用。我们将看到如何通过引入人工智能技术,操作系统能够更加智能化地管理资源,提高系统性能和用户体验。
|
2月前
|
缓存 安全 数据库
探索后端开发的核心原则与实践操作系统的未来:从多任务处理到智能优化
【8月更文挑战第23天】在数字化时代的浪潮中,后端开发作为技术架构的支柱,承载着数据处理、业务逻辑实现和系统性能优化的关键任务。本文将深入探讨后端开发的几大核心原则,包括模块化设计、性能优化、安全性强化及可维护性提升,旨在为读者揭示如何构建一个健壮、高效且安全的后端系统。通过分析这些原则背后的理念及其在实际开发中的应用,本文意在启发读者思考如何在不断变化的技术环境中,持续优化后端开发实践,以适应新的挑战和需求。
|
2月前
|
调度 UED
操作系统中的多任务处理机制
【8月更文挑战第23天】在数字时代,操作系统的核心功能之一是多任务处理。它允许用户同时运行多个程序,优化资源使用,并提高生产效率。本文将深入探讨操作系统如何实现多任务处理,以及这一机制对用户体验和系统性能的影响。通过理解多任务处理的工作原理,用户可以更好地管理计算资源,提升个人和组织的工作效率。
|
2月前
|
人工智能 算法 物联网
操作系统的演变:从单任务到多任务的旅程
【8月更文挑战第20天】在数字时代的浪潮中,操作系统作为计算机系统的核心,经历了从简单的单任务处理到复杂的多任务并行处理的转变。本文将探讨这一转变过程中的关键里程碑,包括早期的批处理系统、多道程序设计的出现、分时系统的创新以及现代操作系统中的多任务处理机制。通过这一旅程,我们将了解操作系统如何适应不断增长的计算需求,并预见未来可能的发展方向。
|
2月前
|
机器学习/深度学习 人工智能 自动驾驶
操作系统的演化之路:从单任务到多任务处理
【8月更文挑战第16天】 本文将探索操作系统(OS)的演进历程,聚焦于它们如何从处理单一任务的简单系统,发展成为能够同时处理多个任务的复杂系统。我们将分析这一转变背后的技术驱动因素,以及它对用户体验和系统性能的影响。文章还将探讨现代操作系统在面对日益增长的计算需求时所面临的挑战,以及未来的发展方向。