?? c04a_semaphore.c
字號:
/* C04a_semaphore.c P72 */
/* 本程序修改自VxWorks5.5的培訓資料 */
/* 頭文件 */
#include "vxWorks.h"
#include "stdio.h"
#include "stdlib.h"
#include "semLib.h"
#include "taskLib.h"
/* 宏定義 */
#define NUM_SAMPLE 10 /* 組成一個樣本的數據的個數 */
#define DELAY_TICKS 8 /* 模擬產生數據的間隔時間 */
#define STACK_SIZE 20000 /* 分配給每個任務的堆棧大小 */
/* 類型定義 */
typedef struct _LIST_NODE
{
int data; /* 節點數據 */
struct _LIST_NODE *pNextNode; /* 指向下一個節點的指針 */
}LIST_NODE;
/* 全局變量 */
int tidCosmos; /* 任務ID定義 */
int tidSchlep;
int tidCrunch;
int tidMonitor;
int cosmicData = 0; /* 模擬產生的數據 */
int result = 0; /* 樣本處理結果 */
LIST_NODE *pCurrNode = NULL; /* 數據列表的頭指針 */
SEM_ID dataSemId; /* 信號量ID,用于同步,數據可用時釋放 */
SEM_ID syncSemId; /* 信號量ID,用于同步,樣本可用時釋放 */
SEM_ID nodeListGuardSemId; /* 信號量ID,用于互斥,保護數據列表 */
/* 函數聲明 */
void cosmos(void);
void nodeAdd(int data);
void schlep(void);
void nodeScrap(void);
void crunch(void);
void monitor(void);
void progStop(void);
/******************************************************************
*
* progStart - 啟動實例程序
*
* 負責創建信號量與任務
*
* RETURNS: OK
*/
STATUS progStart(void)
{
/* 創建信號量 */
syncSemId = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
dataSemId = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
nodeListGuardSemId = semMCreate(SEM_Q_PRIORITY
| SEM_INVERSION_SAFE
| SEM_DELETE_SAFE);
/* 初始化變量 */
pCurrNode = NULL;
/* 創建任務 */
tidCosmos = taskSpawn("tCosmos", 200, 0, STACK_SIZE,
(FUNCPTR)cosmos,0,0,0,0,0,0,0,0,0,0);
tidSchlep = taskSpawn("tSchlep", 220, 0, STACK_SIZE,
(FUNCPTR)schlep,0,0,0,0,0,0,0,0,0,0);
tidCrunch = taskSpawn("tCrunch", 240, 0, STACK_SIZE,
(FUNCPTR) crunch,0,0,0,0,0,0,0,0,0,0);
tidMonitor = taskSpawn("tMonitor", 250, 0, STACK_SIZE,
(FUNCPTR) monitor,0,0,0,0,0,0,0,0,0,0);
return (OK);
}
/******************************************************************
*
* cosmos - 仿真接收中斷的服務程序
*
* 仿真了數據接收ISR(中斷服務程序)所作的工作,
* 每次釋放一次信號量代表數據到來一次
*
* RETURNS: N/A
*/
void cosmos(void)
{
FOREVER
{
/* 制造數據,
* 生成一個偽隨機整數,范圍=[0-RAND_MAX]
*/
cosmicData = rand();
/* 通知數據接收任務 */
semGive(dataSemId);
/* 延遲,保證產生的數據被接收任務處理 */
taskDelay(DELAY_TICKS);
}
return;
}
/******************************************************************
*
* nodeAdd - 將樣本數據存儲到數據鏈表
*
* 申請一個數據節點來保持樣本數據,并將節點前插入數據鏈表中
*
* RETURNS: N/A
*/
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;
}
/*******************************************************************
*
* schlep - 將采集到的數據組成一個樣本
*
* 將采集到的數據,每NUM_SAMPLE個一組,組成一個樣本,樣本用全局的數據鏈表存儲
*
* 每組成一個樣本之后,利用二進制信號量的同步功能,喚醒(Unpend)樣本處理任務
*
* RETURNS: N/A
*/
void schlep(void)
{
int i;
FOREVER
{
for(i = 0; i < NUM_SAMPLE; i++)
{
/* 等數據 */
semTake(dataSemId, WAIT_FOREVER);
/* 保存數據 */
nodeAdd(cosmicData);
}
/* 將單個的樣本發給tCrunch */
semGive(syncSemId);
}
return;
}
/******************************************************************
*
* nodeScrap - 從數據鏈表中刪除首個數據節點
*
* 互斥訪問數據鏈表,完成從數據鏈表中刪除首個數據節點的工作
*
* RETURNS: N/A
*/
void nodeScrap(void)
{
LIST_NODE *pTmpNode; /* 指向首個數據節點 */
/* 互斥訪問數據鏈表 */
semTake(nodeListGuardSemId, WAIT_FOREVER);
if (pCurrNode != NULL)
{
pTmpNode = pCurrNode;
pCurrNode = pCurrNode->pNextNode;
free(pTmpNode);
}
/* 互斥結束 */
semGive(nodeListGuardSemId);
return;
}
/******************************************************************
*
* crunch - 處理樣本數據
*
* 利用二進制信號量的同步功能,等待tSchlep發送一個樣本。
* 對收到的樣本數據進行求和處理。
*
* RETURNS: N/A
*/
void crunch(void)
{
int sampleSum; /* 保存樣本數據之和 */
FOREVER
{
/* 數據清零 */
sampleSum = 0;
/* 同步,等待樣本 */
semTake(syncSemId, WAIT_FOREVER);
/* 互斥訪問數據鏈表 */
semTake(nodeListGuardSemId, WAIT_FOREVER);
while (pCurrNode != NULL)
{
/* 對樣本數據求和 */
sampleSum += pCurrNode->data;
/* 遞歸訪問,刪除數據 */
nodeScrap();
}
/* 互斥結束 */
semGive(nodeListGuardSemId);
/* 更新結果 */
result = sampleSum;
}
}
/*****************************************************************
*
* monitor - 監視程序運行情況
*
* 監視程序運行情況,并顯示結果
* 當result>average時,顯示HOT,反之顯示COOL
*
* RETURNS: N/A
*/
void monitor(void)
{
int isHot = FALSE; /* 標志:TRUE = 熱;FALSE = 冷 */
int average = 0; /* 平均值 */
/* 一個樣本中的數據總數為NUM_SAMPLE
* 每個數據的取值范圍為[0-RAND_MAX]
*/
average = RAND_MAX * NUM_SAMPLE / 2;
FOREVER
{
if ((!isHot) && (result >= average))
{
isHot = TRUE;
printf("HOT\n");
}
else if (isHot && (result < average))
{
isHot = FALSE;
printf("COOL\n");
}
}
return;
}
/*********************************************************************
* progStop - 停止實例程序
*
* 調用本函數來停止本實例程序,刪除創建的任務并釋放信號量資源。
*
* RETURNS: N/A
*/
void progStop(void)
{
/* 互斥信號量有刪除保護功能,
* 必須成功獲得之后再進行刪除任務的工作
*
* nodeScrap()中需要使用互斥信號量
* 必須在刪除互斥信號量調用
*/
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;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -