流水线结构
#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 );
}
}
}