Day3 多线程编程模型之pipeline

《POSIX多线程程序设计》  多线程之流水线模型

示例代码:

pipe_create函数创建一个链表,每一个结点,代表流水线中的一个状态,并在最后附件一个结果状态。之后,启动状态线程pipe_stage,此时stage->data_ready 尚为0,pipe_stage等待条件变量avail.

若主线程接受到的输入合法,则调用pipe_start函数,记录进入pipeline的数据数量。pipe_start中调用pipe_send 发送到pipeline中的第一个结点。pipe_send接收到数据后,置stage->data_ready为1,(表示暂不能接收下一个pip_start调用发送过来的数据),signal avail变量,使pipe_stage将数据,接收并处理。

pipe_stage 接收数据并处理后(此处简单+1),调用pipe_send发送到下一个结点。并把stage->data_ready置0(表明该流水线结点,数据已经被取走处理,可以接收新数据),并signal ready变量,使当前流水线结点接收数据,并处理。

当主线程中接收到打印结果的命令时,调用pipe_result。pipe_result检查pipeline中是否有数据,若有数据,则等待tail->data_ready信号量,如果tail中有结果,则取走该结果,并signal ready信号量,供前面的线程存放产生的结果。

 

 

/*************************************************************************
*  File Name: pipe.c
*  Author: JohnMiller
*  Mail: jfmcs_0211@126.com
*  Created Time: Sat 02 Dec 2017 11:12:41 AM CST
*************************************************************************/

#include <stdio.h>
#include <pthread.h>
#include "../errors/errors.h"

typedef struct stage_tag {
    pthread_mutex_t            mutex;
    pthread_cond_t            avail;
    pthread_cond_t            ready;
    int                        data_ready;
    long                    data;
    pthread_t                thread;
    struct stage_tag        *next;
} stage_t;

typedef struct pipe_tag {
    pthread_mutex_t            mutex;
    stage_t                    *head;
    stage_t                    *tail;
    int                        stages;
    int                        active;
} pipe_t;

int pipe_send(stage_t *stage, long data)
{
    int status;
    status = pthread_mutex_lock(&stage->mutex);
    if(status != 0)
        return status;
    while(stage->data_ready) {
        status=pthread_cond_wait(&stage->ready,&stage->mutex);
        if(status != 0) {
            pthread_mutex_unlock(&stage->mutex);
            return status;
        }

    }

    stage->data = data;
    stage->data_ready = 1;
    status = pthread_cond_signal(&stage->avail); 
    if(status != 0) {
        pthread_mutex_unlock(&stage->mutex);
        return status;
    }
    status = pthread_mutex_unlock(&stage->mutex);
    return status;
}

void *pipe_stage(void *arg)
{
    stage_t *stage = (stage_t *)arg;
    stage_t *next_stage = stage->next;
    int status;

    status = pthread_mutex_lock(&stage->mutex);
    if(status != 0)
        err_abort(status,"Lock pipe stage");

    while(1) {
        while(stage->data_ready != 1) {
            status = pthread_cond_wait(&stage->avail, &stage->mutex);
            if(status != 0)
                err_abort(status,"wait for previous stage");
        }
        pipe_send(next_stage,stage->data+1);
        stage->data_ready = 0;
        status = pthread_cond_signal(&stage->ready);
        if(status != 0)
            err_abort(status,"wake next stage");
    }
    /* Notice that the routine never unlocks the stage->mutex.
     * The call to pthread_cond_wait implicitly unlocks the
     * mutex while the thread is waiting, allowing other threads
     * to make progress. Because the loop never terminates, this
     * function has no need to unlock the mutex explicitly.
     */

}

int pipe_create(pipe_t *pipe, int stages)
{
    int pipe_index;
    stage_t **link = &pipe->head, *new_stage, *stage;
    int status;

    status = pthread_mutex_init(&pipe->mutex, NULL);
    if(status != 0) 
        err_abort(status, "Init pipe mutex");
    pipe->stages = stages;
    pipe->active = 0;

    for(pipe_index = 0; pipe_index <= stages; pipe_index ++) {
        new_stage = (stage_t *)malloc(sizeof(stage_t));
        if(new_stage == NULL)
            errno_abort("Allocate stage");
        status = pthread_mutex_init(&new_stage->mutex, NULL);
        if(status != 0)
            err_abort(status,"Init stage mutex");
        status = pthread_cond_init(&new_stage->avail,NULL);
        if(status != 0)
            err_abort(status,"Init avail condition");
        status = pthread_cond_init(&new_stage->ready, NULL);
        if(status != 0)
            err_abort(status,"Init ready condition");
        new_stage->data_ready = 0;
        *link = new_stage;
        link = &new_stage->next;
    }
    *link = (stage_t *) NULL;    /* Terminate list */
    pipe->tail = new_stage;        /* Record the tail*/
    
    for( stage = pipe->head;
         stage->next != NULL;
         stage = stage->next) {
        
        status = pthread_create(&stage->thread,NULL,pipe_stage, (void*) stage);
        if(status != 0)
            err_abort(status, "create pipe stage");
    }

    return 0;

}

int pipe_start(pipe_t *pipe, long value)
{
    int status;

    status = pthread_mutex_lock(&pipe->mutex);
    if(status != 0)
        err_abort(status, "Lock pipe mutex");
    pipe->active ++;
    status = pthread_mutex_unlock(&pipe->mutex);
    if(status != 0)
        err_abort(status, "unlock pipe mutex");
    pipe_send(pipe->head,value);
    return 0;
}

int pipe_result(pipe_t *pipe, long *result)
{
    stage_t *tail = pipe->tail;
    long value;
    int empty = 0;
    int status;

    status = pthread_mutex_lock(&pipe->mutex);
    if(status != 0)
        err_abort(status,"Lock pipe mutex");
    if(pipe->active <= 0)
        empty = 1;
    else
        pipe->active--;
    
    status = pthread_mutex_unlock(&pipe->mutex);
    if(status != 0)
        err_abort(status, "unlock pipe mutex");
    if(empty)
        return 0;
    
    pthread_mutex_lock(&tail->mutex);
    while(!tail->data_ready)
        pthread_cond_wait(&tail->ready,&tail->mutex);
    *result = tail->data;
    tail->data_ready = 0;
    pthread_cond_signal(&tail->ready);
    pthread_mutex_unlock(&tail->mutex);
    return 1;
}

int main(int argc, char *argv[])
{
    pipe_t my_pipe;
    long value, result;
    int status;
    char line[128];

    pipe_create(&my_pipe,10);
    printf("Enter integer values, or \"=\" for next result\n");

    while(1) {
        printf("Data> ");
        if(fgets(line,sizeof(line),stdin) == NULL)    exit(0);
        if(strlen(line) <=1)    continue;
        if(strlen(line) <= 2 && line[0] == '='){
            if(pipe_result(&my_pipe,&result))
                printf("Result is %ld\n",result);
            else
                printf("pipe is empty\n");                    
        } else {
            if(sscanf(line,"%ld",&value) <1 )
                fprintf(stderr,"Enter an integer value\n");
            else
                pipe_start(&my_pipe, value);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/jfm-cs/p/7955162.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值