线程的组织方式:流水线结构

流水线结构

#include <pthread.h>
#include "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, *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 ) { // 如果有数据,则下面必须等待知道收到ready信号
    status = pthread_cond_wait( &stage -> ready, &stage -> mutex );
    if( status != 0 ) {
      pthread_mutex_unlock( &stage -> mutex );
      return status;
    }
  }
  // 空闲则可以继续执行,传递data,置就绪位
  stage -> data = data;
  stage -> data_ready = 1;
  // 此时有了data,就可以发送avail信号了
  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; // 下一个线程stage_t结构
  int status;

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

  while( 1 ) {
    while( stage -> data_ready != 1 ) {
      // 一开始data_ready是0,所以到这里一定会等待avail 
      // 如果数据已经就绪,则跳过这个while
      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发送数据
    stage -> data_ready = 0; //之后这一个stage空闲,下面发送ready信号,继续处理数据
    status = pthread_cond_signal( &stage -> ready );
    if( status != 0 )
      err_abort( status, "wake next stage" );
  }
}


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;
  pipe -> tail = new_stage;

  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 ); // 从第一个stage激活流水线
  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 -> avail, &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 );
    }
  }
}


阅读更多
上一篇头文件errors.h
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭