本文介绍了三种构建线程解决方案的方式。

一、流水线:每个线程执行同一种操作,并把操作结果传递给下一步骤的线程。

代码示例如下:
终端输入一个int值,每个线程将该值加1,并将结果传给下一个线程。

#include<stdio.h>
#include<pthread.h>
typedef struct stage_tag
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int data;
int ready;
pthread_t tid;
struct stage_tag *next;
}stage_t;
typedef struct pipe_tag
{
pthread_mutex_t mutex;
stage_t *head;
stage_t *tail;
int stages;
}pipe_t;
void pipe_send(stage_t *stage,int data)
{
stage->data =data;
stage->ready = ;
pthread_cond_signal(&stage->cond);
}
void *thread_route(void *arg)
{
stage_t *stage = (stage_t *)arg;
while(!stage->ready)
{
pthread_cond_wait(&stage->cond,&stage->mutex);
}
int data = stage->data+;
stage_t *next = stage->next;
if(next!=NULL)
{
pipe_send(next,data);
}
return NULL;
}
void create_pipe(pipe_t *pipe,int stages)
{
// pipe = (pipe_t *)malloc(sizeof(pipe_t));
pipe->stages = stages;
int i;
stage_t *stage;
stage_t *last;
for(i=;i<=stages;i++)
{
stage = (stage_t *)malloc(sizeof(stage_t));
stage->data = i;
if(i==)
{
pipe->head = stage;
}
if(last!=NULL)
{
last->next = stage;
}
last = stage;
}
last->next=NULL;
pipe->tail = last;
for(stage=pipe->head;stage->next!=NULL;stage=stage->next)
{
pthread_create(&stage->tid,NULL,thread_route,(void *)stage);
printf("stage %d\n",stage->data);
}
/* free(pipe);
for(stage=pipe->head;stage!=NULL;stage=stage->next)
{
free(stage);
}
*/
}
int main(void)
{
pipe_t my_pipe;
long value,result;
char line[];
create_pipe(&my_pipe,);
pipe_send(my_pipe.head,);
sleep();
printf("result is %d\n",my_pipe.tail->data);
return ;
}

二、工作组:数据由一组线程分别独立地处理。

代码示例如下:
程序有两个参数:filepath:文件或目录路径;search:待查找字符串

程序将文件路径排队给工作组,工作组线程判断该路径是文件还是目录,如果是文件,它将在文件中搜索字符串;如果是目录,它将使用readdir_r查找该目录中的所有子目录和文件,并将每一项添加到工作队列。

#include<stdio.h>
#include<pthread.h>
#include<dirent.h>
#include<sys/stat.h>
typedef struct work_tag
{
struct work_tag *next;
char *path;
char *search;
}work_t,*work_p;
typedef struct worker_tag
{
int index;
pthread_t tid;
struct crew_tag *crew; }worker_t,*worker_p;
typedef struct crew_tag
{
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_cond_t done;
long work_count;
work_t *first,*last;
worker_t workers[];
}crew_t,*crew_p;
void *thread_route(void *arg)
{
worker_p worker = (worker_t *)arg;
crew_p crew = worker->crew;
struct dirent *entry;
entry = (struct dirent*)malloc(sizeof(struct dirent)+sizeof(size_t));
pthread_mutex_lock(&crew->mutex);
while(crew->work_count ==)
{
pthread_cond_wait(&crew->cond,&crew->mutex);
}
pthread_mutex_unlock(&crew->mutex);
printf("worker is running: %d\n",worker->index);
while()
{
pthread_mutex_lock(&crew->mutex);
while(crew->first==NULL)
{
pthread_cond_wait(&crew->cond,&crew->mutex);
}
printf("worker %d woke %#lx %d\n",worker->index,crew->first,crew->work_count);
work_p work = crew->first;
crew->first = work->next;
if(crew->first==NULL)
crew->last = NULL;
printf("worker %d took %#lx,leave first %#lx,last %#lx\n",worker->index,work,crew->first,crew->last);
pthread_mutex_unlock(&crew->mutex);
struct stat filestat;
lstat(work->path,&filestat);
if(S_ISLNK(filestat.st_mode))
printf("worker %d:%s is a link,skipping.\n",worker->index,work->path);
else if(S_ISDIR(filestat.st_mode)){
DIR *dir;
struct dirent *result;
dir = opendir(work->path);
while(){
readdir_r(dir,entry,&result);
if(result==NULL)
break;
if(strcmp(entry->d_name,".")==)
continue;
if(strcmp(entry->d_name,"..")==) continue;
work_p new_work = (work_p)malloc(sizeof(work_t));
printf("test\n");
path_max = pathconf (work->path, _PC_PATH_MAX);
new_work->path = (char*)malloc (path_max);
strcpy (new_work->path, work->path);
strcat (new_work->path, "/");
strcat (new_work->path, entry->d_name);
// char *new_dir = strcat(work->path,entry->d_name);
//new_work->path = new_dir;
new_work->search = work->search;
new_work->next = NULL;
pthread_mutex_lock(&crew->mutex);
if(crew->first==NULL)
{
crew->first = new_work;
crew->last = new_work;
}
else{
crew->last->next = new_work;
crew->last = new_work;
}
crew->work_count++;
printf("worker %d add work %#lx,first %#lx,last %#lx,%d\n",worker->index,new_work,crew->first,crew->last,crew->work_count);
pthread_cond_signal(&crew->cond);
pthread_mutex_unlock(&crew->mutex);
}
closedir(dir);
}
else if(S_ISREG(filestat.st_mode)){
FILE *file;
char buffer[];
file = fopen(work->path,"r");
fgets(buffer,sizeof(buffer),file);
char *search_ptr;
search_ptr = strstr(buffer,work->search);
if(search_ptr!=NULL){
printf("worker %d found \"%s\" in %s\n ",worker->index,work->search,work->path);
}
fclose(file); }
else{
printf("worker %d:%s format is error.\n",worker->index,work->path);
}
free(work->path);
free(work); pthread_mutex_lock(&crew->mutex);
crew->work_count--;
printf("worker %d decremented work to %d\n",worker->index,crew->work_count);
if(crew->work_count<=){
pthread_cond_broadcast(&crew->done);
}
pthread_mutex_unlock(&crew->mutex);
}
free(entry);
return NULL;
}
void crew_create(crew_t *crew)
{
int worker_index;
crew->work_count = ;
crew->first = NULL;
crew->last = NULL;
pthread_mutex_init(&crew->mutex,NULL);
pthread_cond_init(&crew->cond,NULL);
pthread_cond_init(&crew->done,NULL);
for(worker_index=;worker_index<;worker_index++){
crew->workers[worker_index].index = worker_index;
crew->workers[worker_index].crew = crew;
pthread_create(&crew->workers[worker_index].tid,
NULL,thread_route,(void *)&crew->workers[worker_index]);
}
}
void crew_start(crew_t *crew,char *filepath,char *search)
{
pthread_mutex_lock(&crew->mutex);
work_p work = (work_p)malloc(sizeof(work_t));
work->path = filepath;
work->search = search;
work->next = NULL;
crew->first = work;
crew->last = work;
crew->work_count++;
pthread_cond_signal(&crew->cond);
while(crew->work_count>)
{
pthread_cond_wait(&crew->done,&crew->mutex);
}
printf("crew is done!\n");
pthread_mutex_unlock(&crew->mutex);
}
int main(void)
{
crew_t crew;
crew_create(&crew);
char *filepath = "/home/ubuntu/programs";
char *search = "errno";
crew_start(&crew,filepath,search);
return ;
}

三、客户端/服务器:客户端线程将工作排队,交给一个服务器线程去处理。客户端或者以同步方式等待服务器执行,或异步执行并在后面需要时查找结果。

代码示例如下:
一组线程都需要从stdin中读取输入,这将导致提示-读(prompt-and-read)操作可能有些混乱。一个方法是使用flockfile和funlockfile函数来锁住stdin和stdout。,另一个方式是,使用服务器线程,将客户端读写操作排队,由服务器线程依次处理读写操作队列。

#include<stdio.h>
#include<pthread.h>
#define REQ_READ 1
#define REQ_WRITE 2
#define REQ_QUIT 3
typedef struct client_tag
{
struct client_tag *next;
int oper;
int sync;
int done_flag;
char prompt[];
char text[];
pthread_mutex_t mutex;
pthread_cond_t mutex;
}client_t;
typedef struct server_tag
{
client_t *first,*last;
pthread_mutex_t mutex;
pthread_cond_t cond;
}server_t;
server_t server={NULL,NULL,PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER};
pthread_mutex_t main_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t main_cond = PTHREAD_COND_INITIALIZER;
int thread_count = ;
void client_request(int oper,int sync,const char *prompt,char *string)
{
pthread_mutex_lock(&server.mutex);
client_t *client;
client = (client_t *)malloc(sizeof(client_t));
client->next = NULL;
client->oper = oper;
client->sync = sync;
if(prompt!=NULL)
strncpy(client->prompt,prompt,);
if(oper==REQ_WRITE&&string!=NULL)
strncpy(client->text,string,);
if(server.first==NULL)
{
server.first = client;
server.last = client;
}else{
server.last->next = client;
server.last = client;
}
pthread_cond_signal(&server.cond);
if(sync)
{
while(!client->done_flag)
{
pthread_cond_wait(&client->cond,&server.mutex);
}
if(oper==REQ_READ)
{
if(strlen(client->text)>)
strcpy(string,client->text);
}
}
pthread_cond_destroy(&client->cond);
free(request);
}
pthread_mutex_unlock(&server.mutex);
}
void *client_route(void *arg)
{
int index = (int)arg;
int loops;
char prompt[];
char string[],formatted[];
sprintf(prompt,"Client %d>",index);
while()
{
client_request(REQ_READ,,prompt,string);
if(strlen(string)==)
break;
for(loops=;loops<;loops++)
{
sprintf(formatted,"(%d#%d) %s",index,loops,string);
client_request(REQ_WRITE,,NULL,formatted);
sleep();
}
}
}
void *server_route(void *arg)
{
client_t *client;
int oper;
while()
{
pthread_mutex_lock(&server.mutex);
while(server.first==NULL)
{
pthread_cond_wait(&server.cond,&server.mutex);
}
client = server.first;
server.first = client.next;
if(server.first==NULL)
server.last = NULL;
pthread_mutex_unlock(&server.mutex);
oper = client->oper;
switch(oper){
case REQ_QUIT:
break;
case REQ_READ:
if(strlen(client->prompt)>)
printf(client->prompt);
fgets(client->text,,stdin);
break;
case REQ_WRITE:
puts(client->text);
break;
default:
break;
}
free(client);
if(oper==REQ_QUIT)
break;
}
return NULL;
}
int main(void)
{
pthread_t sid;
pthread_create(&sid,NULL,server_route,NULL); pthread_t cid;
int i;
for(i=;i<thread_count;i++)
{
pthread_create(&cid,NULL,client_route,(void *)count);
}
pthread_mutex_lock(&main_mutex);
while(thread_count>)
{
pthread_cond_wait(&main_cond,&main_mutex);
}
pthread_mutex_unlock(&main_mutex);
printf("Done!\n");
client_request(REQ_QUIT,,NULL,NULL);
return ;
}

参考资料:《POSIX多线程程序设计》 pp.81-110

posix多线程--三种基本线程编程模型的更多相关文章

  1. 多线程(三) java中线程的简单使用

    java中,启动线程通常是通过Thread或其子类通过调用start()方法启动. 常见使用线程有两种:实现Runnable接口和继承Thread.而继承Thread亦或使用TimerTask其底层依 ...

  2. 【Java 线程的深入研究1】Java 提供了三种创建线程的方法

    Java 提供了三种创建线程的方法: 通过实现 Runnable 接口: 通过继承 Thread 类本身: 通过 Callable 和 Future 创建线程. 1.通过实现 Runnable 接口来 ...

  3. JAVA基础知识之多线程——三种实现多线程的方法及区别

    所有JAVA线程都必须是Thread或其子类的实例. 继承Thread类创建线程 步骤如下, 定义Thead子类并实现run()方法,run()是线程执行体 创建此子类实例对象,即创建了线程对象 调用 ...

  4. Android 中三种启用线程的方法

    在多线程编程这块,我们经常要使用Handler(处理),Thread(线程)和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢? 首先说明Android的CPU分配的最小单元是线程,Han ...

  5. Java 多线程 三种实现方式

    Java多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...

  6. JAVA多线程三种实现方式

    JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...

  7. java线程(1)——三种创建线程的方式

    前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...

  8. java线程——三种创建线程的方式

    前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...

  9. 三种Shell脚本编程中避免SFTP输入密码的方法

    最近编程中用到sftp上传文件,且需要用crontab预设定时上传事件.而sftp不同于ftp,没有提供选项如 -i 可以将密码直接编码进程序.使用sftp指令,会自动请求用户输入密码. 总结一下可以 ...

随机推荐

  1. Flume-0.9.4数据插入HBase-0.96

    来自:http://blog.csdn.net/iam333/article/details/18770977 最近由于业务需要,需要将flume的数据插入HBase-0.96,利用flume的实时日 ...

  2. Python 的时间格式化

    对于像'Wed, 11 Apr 2012 09:37:05 +0800'的时间格式化可如下解: >>> date='Wed, 11 Apr 2012 09:37:05 +0800'& ...

  3. WebStorm配置

    一.主题配色 主题设置方法:File -> Settings -> Appearance & Behavior -> Appearance ->Theme. webst ...

  4. win7 mtp

    Sensors MTP Monitor Service 允许MTP设备数据传输,如果该服务被禁用,MTP监视器将不能工作.该服务的默认运行方式是手动,如果你没有使用MTP设备,该功能就可以放心禁用.  ...

  5. 解决/usr/lib/libstdc++.so.6: version `GLIBCXX_3.4.15' not found错误的解决

    原因是没有GLIBCXX_3..15版本,或是更高的版本. 一.查看并下载 32位系统: [root@localhost ~]# strings /usr/lib/libstdc++.so. | gr ...

  6. MariaDB删除重复记录

    不管是程序BUG,还是业务变更,重复数据这个老生常谈的问题,总是会出现.以下是我在MariaDB或是MySQL下处理的一些经验.在SQL Server中,使用窗口函数是很容易实现的.不过听说MySQL ...

  7. oracle date日期类型 精析

      一.date 1.date.sysdate格式说明 展示 date类型,展示格式既可以为:YYYY/MM/DD,也可以为YYYY/MM/DD HH24:MI:SS: 其存储格式只有一种:YYYY/ ...

  8. (转)J2EE十三个技术规范

    从事Java开发的童鞋都知道,java是一种非常棒的语言,能够实现跨平台运行.它屏蔽了具体的平台环境的要求,也就是说,无论是windows,还是Unix.Linux系统,只要支持Java虚拟机,就可以 ...

  9. TP3.2批量上传文件(图片),解决同名冲突问题

    1.html <form action="{:U('Upload/index')}" enctype="multipart/form-data" meth ...

  10. MySQL-事务隔离级别设置

    加锁研究:http://www.cnblogs.com/JohnABC/p/4377529.html 先了解下 第一类丢失更新.脏读.不可重复读.幻读.第二类丢失更新 第一类丢失更新 撤销一个事务时, ...