续上一篇《简单的多线程流水线模型(一)》
下面我们创建三个工人 Lucy,Lily,Lilei,他们干的活就是接收输入的秒数input,把睡眠input秒,然后把input-1丢给下一个工人。
这里做一下小结:
流水线模型的优缺点。
优点:一环扣一环,确保事情按顺序一个一个干完。
缺点:流水线的某个环节如果处理速度慢的话,会影响上游的整个流水线,所以流水线的瓶颈应该是花时间最多的那个环节。如何调度,这个后面再讨论。
下面的实现多个工人的流水线,这里是假设每个工人干的活差不多,实际使用的时候,可以为每个环节写不同的thread_worker,这样就可以做一些更灵活的工作了!
代码如下:
#include <pthread.h>
#include <time.h>
#include "errors.h"
#define WORKERS_TOTAL 3
struct worker_type{
pthread_mutex_t mtx;
pthread_cond_t cond_has_input;
pthread_cond_t cond_has_finished;
int has_input;
int has_finished;
pthread_t thread_id;
void * (*thread_worker)(void *);// The thread of this worker
struct worker_type * next;
//below if optionally, corresponding to your demands
char *name; // The worker's name
int input_data; // The input data
};
typedef struct worker_type worker_t;
typedef struct pipeline_type{
int count;
worker_t * head;
worker_t * tail;
}pipeline_t;
void * send_input_to_worker(worker_t *worker, int input)
{
//1. Catch the lock
pthread_mutex_lock(&worker->mtx);
//2. Waiting for the worker finish the job
while(!worker->has_finished){
pthread_cond_wait(&worker->cond_has_finished,&worker->mtx);
}
//3. Pass the input to the worker.
worker->has_input = 1;
worker->has_finished = 0;
worker->input_data = input;
pthread_cond_signal(&worker->cond_has_input);
//4. Unlock
pthread_mutex_unlock(&worker->mtx);
return NULL;
}
void * thread_worker(void *arg)
{
//1. Before looping ,do something initial.
worker_t * worker = (worker_t *)arg;
struct timespec t;
int status;
int input;
t.tv_nsec = 0;
//2. Looping
while(1){
//2.1 Lock the worker before access its value
pthread_mutex_lock(&worker->mtx);
//2.2 Waiting for the input
while(!worker->has_input){
printf("%s: Give me the job!\n",worker->name);
status = pthread_cond_wait(&worker->cond_has_input,&worker->mtx);
}
//2.3 Fetch the input,processing
input = worker->input_data;
printf("%s: %d received! Process %d seconds\n",worker->name,input,input);
sleep(input);//process
if(worker->next != NULL){
send_input_to_worker(worker->next,input-1);
}else{
printf("%s: Nobody works for me!\n",worker->name);
}
worker->has_input = 0;
worker->has_finished = 1;
//2.4 After processing, send the signal and unlock the mutex
pthread_cond_signal(&worker->cond_has_finished);
pthread_mutex_unlock(&worker->mtx);
}
}
void *pipe_line_start(pipeline_t * pipeline_p)
{
worker_t *worker_p, **worker_pp;
char * names[] = {"Lucy ","Lily ","Lilei"};
int i;
worker_pp = &pipeline_p->head;
for(i = 0; i < WORKERS_TOTAL ;i++){
*worker_pp = (worker_t *)malloc(sizeof(worker_t));
worker_p = *worker_pp;
worker_p->name = names[i];
worker_p->thread_worker = thread_worker;
worker_p->has_input = 0;
worker_p->has_finished = 1;
pthread_mutex_init(&worker_p->mtx,NULL);
pthread_cond_init(&worker_p->cond_has_input,NULL);
pthread_create(&worker_p->thread_id,NULL,worker_p->thread_worker,worker_p);
worker_pp = &worker_p->next;
}
pipeline_p->tail = *worker_pp;
worker_p->next = NULL;
return NULL;
}
int main(int argc, char *argv[]){
int i;
pipeline_t pipeline1,;
pipe_line_start(&pipeline1);
while(1){
scanf("%d",&i);
send_input_to_worker(pipeline1.head,i);
}
pthread_exit(NULL);
return 0;
}
输出结果:
[hackooo@localhost c]$ gcc -lpthread ti.c
[hackooo@localhost c]$ ./a.out
Lilei: Give me the job!
Lily : Give me the job!
Lucy : Give me the job!
4
Lucy : 4 received! Process 4 seconds //等待4秒
Lucy : Give me the job!
Lily : 3 received! Process 3 seconds //等待3秒
Lily : Give me the job!
Lilei: 2 received! Process 2 seconds //等待2秒
Lilei: Nobody works for me!
Lilei: Give me the job!
^C
[hackooo@localhost c]$