POSIX 工作流 :
每个线程反复的在数据系列集上执行同一种操作,并把操作结果传递给下一步骤的其他线程。
每个线程由 stage_t 描述:
一个互斥量 m_mutex
两个条件变量:
m_ready_cond:表示当前的线程准备好处理新数据
m_available_cond:表示通知下一步数据已经可用
整个流水线由 pipe_t 描述,构造了一个流水线的队列。
handle_message 和 send 方法是线程的核心用来处理当前的消息和向下一步处理发送数据。
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct _stage_t
{
pthread_t m_tid;
int m_tIdx;
pthread_mutex_t m_mutex;
pthread_cond_t m_ready_cond;
pthread_cond_t m_available_cond;
int m_ready;
int m_act;
char m_data[80];
struct _stage_t* m_next;
} stage_t;
typedef struct _pipe_t
{
stage_t* m_head;
stage_t* m_tail;
int m_stages;
pthread_mutex_t m_mutex;
int m_active;
} pipe_t;
typedef struct _msg_struct
{
int m_msgID;
int m_value;
char m_buff[64];
} msg_t;
void send(stage_t* pStage, char *pData, int nAct)
{
if ((NULL == pStage) || (NULL == pData))
{
return;
}
pthread_mutex_lock(&pStage->m_mutex);
while(pStage->m_ready)
{
pthread_cond_wait(&pStage->m_ready_cond, &pStage->m_mutex);
}
pStage->m_ready = 1;
pStage->m_act = nAct;
memcpy(pStage->m_data, pData, sizeof(msg_t));
pthread_cond_signal(&pStage->m_available_cond);
pthread_mutex_unlock(&pStage->m_mutex);
}
void* handle_message(void* arg)
{
stage_t* pStage = NULL;
if (NULL == arg)
{
return;
}
pStage = (stage_t*) arg;
msg_t* pMsg = (msg_t*)&pStage->m_data;
pthread_mutex_lock(&pStage->m_mutex);
while(1)
{
while(pStage->m_ready != 1)
{
pthread_cond_wait(&pStage->m_available_cond, &pStage->m_mutex);
}
printf("tid=%d recv msg: %s\n",
pStage->m_tIdx, pMsg->m_buff);
pMsg->m_value += 2;
sprintf(pMsg->m_buff, "MsgID=%d, value%d\n", pMsg->m_msgID, pMsg->m_value);
pStage->m_ready = 0;
if (pStage->m_next != NULL)
send(pStage->m_next, (char*)pMsg, pStage->m_act);
pthread_cond_signal(&pStage->m_ready_cond);
}
}
void create_pipe(pipe_t* pipe, int size)
{
int i = 0;
stage_t* pnew = NULL;
stage_t* head = NULL;
stage_t* p = NULL;
if (NULL == pipe)
return;
pthread_mutex_init(&pipe->m_mutex, NULL);
pipe->m_stages = size;
pipe->m_active = 0;
for (i = 0; i < size; i++)
{
pnew = (stage_t*)malloc(sizeof(stage_t));
pthread_mutex_init(&pnew->m_mutex, NULL);
pthread_cond_init(&pnew->m_ready_cond, NULL);
pthread_cond_init(&pnew->m_available_cond, NULL);
pnew->m_ready = 0;
memset(pnew->m_data, 0, 80);
pnew->m_next = NULL;
pnew->m_tIdx = i;
if (i == 0)
{
head = pnew;
p = pnew;
}
else
{
p->m_next = pnew;
p = p->m_next;
}
}
pipe->m_head = head;
pipe->m_tail = pnew;
for (p = pipe->m_head; p->m_next != NULL; p = p->m_next)
{
pthread_create(&p->m_tid, NULL, handle_message, (void*)p);
}
}
int pipe_start(pipe_t* p, char* msg, int nAct)
{
pthread_mutex_lock(&p->m_mutex);
p->m_active++;
pthread_mutex_unlock(&p->m_mutex);
if (NULL == msg)
{
printf("pipe_start: msg is NULL \n");
return 0;
}
send(p->m_head, msg, nAct);
}
int pipe_result(pipe_t* p)
{
pthread_mutex_lock(&p->m_tail->m_mutex);
msg_t* stMsg = (msg_t*) p->m_tail->m_data;
if (stMsg == NULL)
{
pthread_mutex_unlock(&p->m_tail->m_mutex);
return 0;
}
while(!p->m_tail->m_ready)
{
pthread_cond_wait(&p->m_tail->m_available_cond,
&p->m_tail->m_mutex);
}
printf("last tid=%d recv msg=%s\n", p->m_tail->m_tIdx,
stMsg->m_buff);
memset(&p->m_tail->m_data, 0, 80);
p->m_tail->m_ready = 0;
pthread_cond_signal(&p->m_tail->m_ready_cond);
pthread_mutex_unlock(&p->m_tail->m_mutex);
return 0;
}
int main()
{
pipe_t* pWF = NULL;
char buff[32];
int nCnt = 0;
msg_t stMsg;
pWF = (pipe_t*)malloc(sizeof(pipe_t));
pthread_mutex_init(&pWF->m_mutex, NULL);
pWF->m_head = NULL;
pWF->m_tail = NULL;
pWF->m_stages = 0;
pWF->m_active = 0;
create_pipe(pWF, 5);
while(1)
{
sprintf(stMsg.m_buff, "this is Msg %d\n", nCnt);
printf("Pipe Start: %d\n", nCnt);
stMsg.m_value = nCnt;
stMsg.m_msgID = nCnt;
pipe_start(pWF, (char*)&stMsg, nCnt);
nCnt++;
sleep(2);
pipe_result(pWF);
}
return 0;
}