简单的多线程流水线模型(一)

流水线这个概念应该比较好理解,如一个工厂里,有一堆原料 --> 工人1加工 --> 工人2加工  --> 工人3加工 --> ... ->形成最终的产品。

下面写个简单的流水线实现的模型。


以工人2为例分析工人的整个工作过程:

循环开始:

  a.等待工人1的输入,要是工人1没输入,工人2就趴在工作台上睡觉。

  b.工人1有输出给工人2,发现工人2此时在睡觉呢,空闲着呢,因此工人1把东西往工人2的工作台上一扔,吼一声把工人2 叫醒。

  c.工人2拿到输入后,开始忙活,一阵手忙脚乱。

      此时要是工人1干得快,有输入给工人2,工人2就会嚣张得说,给老子等着,没看见老子正忙活呢!先睡觉去吧你,等老子忙完了叫你起来。工人1就老老实实睡觉去了。

  d.工人2把输入加工完,就会一直等到工人3空闲了,把东西丢给工人3,才算处理完成。

  e.工人2 处理完啦,就对工人1大吼一声,“给老子起来,快把东西给我,老子要干活”。(工人1醒来后第一件事当然是尽快把手头的活忙完然后把输入给工人2了。)

继续从a开始循环。


下面先从一个简单的例子开始,一步一步实现整个流水线(这里没做一些错误检查等等)。

假设现在我们有个一worker,它的任务就是接收一个数字input,如果 input>3,它就睡眠 input秒后醒来,如此循环。

error.h

#ifndef __errors_h
#define __errors_h

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef DEBUG
# define DRPRINTF(arg) printf arg
#else
# define DRPINTF(arg)
#endif

#define err_abort(code,text) do { \
  fprintf(stderr, "%s at \"%s\":%d: %s\n",text, __FILE__,__LINE__,strerror(code));\
  abort();\
  } while(0)

#define errno_abort(text) do{\
  fprintf(stderr, "%s at \"%s\":%d: %s\n",\
    text, __FILE__,__LINE__,strerror(errno));\
	abort();\
	}while(0)
#endif

main.c

#include <pthread.h>
#include <time.h>
#include "errors.h"

/**
worker_type,一个worker实体的数据结构。 mtx是访问整个工人实体的锁。另外工人需要两个谓词(来标注自己的状态1.has_input,是否有输入,2.has_finished,是否已经处理完)
    thread_worker是工人实际工作的线程,工人有指向下一个工人的指针next。
    其它成员时可选的,根据实际情况和需要,这里我设置了两个成员,一个工人的名字,还有一个整形的输入。
*/
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;

/**
pipeline_type,流水线的数据结构,因为这个例子并没用到多个工人,所以这个结构还不完整。
*/
typedef struct pipeline_type{
	int       count;
    worker_t * head;
    worker_t * tail;
}pipeline_t;
/**
工人干活的线程,基本循环:
1.等待前干些准备工作;
2.等待输入;注意这里pthread_cond_timewait和pthread_cond_wait在等待的过程是这样的:首先释放锁,等待信号,拿到信号后,请求锁,直到拿到锁之后函数才返回(如果设置超时就超时后返回)。
3.处理输入;
4.发送信号,解锁
*/
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){
		    //2.2.1  Do something while waiting
#if 0
			printf("Has something to eat? I just wait for 3s to answer\n");
			t.tv_sec = time(0)+3;
			//       Here you can set timeout and do other thing after timeout.
			status = pthread_cond_timedwait(&worker->cond_has_input,&worker->mtx,&t);
			if(status == ETIMEDOUT){
				printf("Nothing to eat,KFC!\n");
			}
#endif
			printf("Hello,can I help you?\n");
			status = pthread_cond_wait(&worker->cond_has_input,&worker->mtx);
		}

		//2.3 Fetch the input,processing
		input = worker->input_data;
		printf("Oh,yes! Has something to eat! Eat it! Let me eat %d\n",input);
		sleep(input);//process
		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);
	}
}
/**
下面这个是两个工人间处理工作交接的过程。
例如:工人1试图访问工人2的状态,等到工人2发信号说他把活干完了,才把东西塞给工人2,然后发送信号给工人2。
*/
void * send_input_to_worker(worker_t *worker, int input)
{
    //1. Catch the lock
	pthread_mutex_lock(&worker->mtx);
	//printf("Input %d get lock\n",input);
	//2. Waiting for the worker finish the job
	while(!worker->has_finished){
	    // Do something while waiting, here you can use the timeout option too.
		//printf("Input %d wait for eat end, unlock\n",input);
		pthread_cond_wait(&worker->cond_has_finished,&worker->mtx);
	}
	//3. Pass the input to the worker.
	//printf("Input %d get lock again\n",input);
	if(input > 3){
		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;
}
/**
这个流水线并不完整,这里只初始化了一个工人,另外一个工人就是我们自己啦,main函数,接收输入然后丢给工人。
*/
void *pipe_line_start_1(pipeline_t * pipeline_p)
{
    worker_t *worker_p;
    pipeline_p->head = (worker_t *)malloc(sizeof(worker_t));

	//initial the head worker
	worker_p = pipeline_p->head;
	worker_p->name = "Lucy";
	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);

	return NULL;
}
int main(int argc, char *argv[]){
    int i;
    pipeline_t pipeline1;
	pipe_line_start_1(&pipeline1);

	while(1){
		scanf("%d",&i);	
		send_input_to_worker(pipeline1.head,i);
	}
	pthread_exit(NULL);
	return 0;
}

未完,待续...


  


### 多线程环境下的流水线工作流程 在多线程环境中,流水线(Pipeline)模式可以显著提高程序效率并简化并发控制。通过将任务分解为多个阶段,并让不同线程负责不同的处理阶段,能够有效利用计算资源。 #### 流水线的基本概念 流水线是种分阶段执行的任务模型,在该模型下整个过程被划分为若干个连续的小部分或步骤,每个步骤称为个“站”。数据项依次经过各个站点完成全部加工[^2]。 #### 实现方式 为了更好地理解这机制,下面给出多线程环境下基于Python语言简单例子来展示如何构建这样的管道: ```python from threading import Thread, Lock import queue class PipelineStage(Thread): def __init__(self, input_queue, output_queue=None): super().__init__() self.input_queue = input_queue self.output_queue = output_queue def process_item(self, item): raise NotImplementedError() def run(self): while True: try: item = self.input_queue.get(timeout=0.1) result = self.process_item(item) if self.output_queue is not None and result is not None: self.output_queue.put(result) self.input_queue.task_done() except queue.Empty: break def create_pipeline(stages_definitions): queues = [] for i in range(len(stages_definitions)): q_in = queue.Queue() if i == 0 else queues[-1] stage_class, args = stages_definitions[i] next_q_out = queue.Queue() if (i + 1) != len(stages_definitions) else None thread = stage_class(q_in, next_q_out, *args) thread.start() queues.append(next_q_out) if __name__ == "__main__": class StageOne(PipelineStage): def process_item(self, item): print(f"Processing {item} at Stage One.") return f"{item}_processed" class StageTwo(PipelineStage): def process_item(self, item): print(f"Processing {item} at Stage Two.") return f"{item.upper()}" pipeline_stages = [ (StageOne,), (StageTwo,) ] p_line = create_pipeline(pipeline_stages) main_input_queue = p_line[0] items_to_process = ["data1", "data2"] for data in items_to_process: main_input_queue.put(data) main_input_queue.join() ``` 上述代码展示了创建两个简单的流水线阶段的方法,其中`create_pipeline()`函数接收系列定义好的类及其参数列表作为输入,并启动相应的线程实例;每个`PipelineStage`继承自标准库中的Thread基类,实现了基本的数据传递逻辑以及具体的业务方法`process_item()`用于实际处理传入的对象。 此设计允许开发者轻松扩展新的处理单元而不影响现有结构,同时也支持异步I/O和其他形式的阻塞操作而不会阻碍其他组件继续运行。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值