POSIX多线程程序设计(第7章:Real code)
来源:互联网 发布:骆驼奶骗局知乎 编辑:程序博客网 时间:2024/06/15 04:26
实例1:barriers
Barrier通常被用来确保某些并行算法中的所有合作线程在任何线程可以继续运行之前到达算法中的一个特定点。即barrier被用来停止线程,当要求的线程数量到达barrier时,所有线程被允许继续运行。
/*barrier.h*/#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <errno.h>typedef struct barrier_tag{ pthread_mutex_t mutex; pthread_cond_t cond; int threadshold;/*工作队列中线程的数量*/ int counter;/*barrier的线程数量*/ unsigned long cycle;/*周期标志*/ int valid;}barrier_t;#define BARRIER_VALID 0xdbcafe/*静态初始化barrier*/#define BARRIER_INITIALIZER(cnt) \ {PTHREAD_MUTEX_INITIZLIZER, PTHREAD_COND_INITIALIZER, \ cnt, cnt, 0, BARRIER_VALID}extern void barrier_init(barrier_t *barrier, int count);extern int barrier_destroy(barrier_t *barrier);extern int barrier_wait(barrier_t *barrier);
/*barrier.c*/#include "barrier.h"/*初始化barrier*/void barrier_init(barrier_t *barrier, int count){ pthread_mutex_init(&barrier->mutex, NULL); pthread_cond_init(&barrier->cond, NULL); barrier->threadshold = barrier->counter = count; barrier->cycle = 0; barrier->valid = BARRIER_VALID; return ;}/*销毁barrier*/int barrier_destroy(barrier_t *barrier){ if (barrier->valid != BARRIER_VALID) { return EINVAL; } pthread_mutex_lock(&barrier->mutex); if (barrier->counter != barrier->threadshold) { pthread_mutex_unlock(&barrier->mutex); return EBUSY; } barrier->valid = 0; pthread_mutex_unlock(&barrier->mutex); pthread_mutex_destroy(&barrier->mutex); pthread_cond_destroy(&barrier->cond); return 0;}/*遇到barrier则线程等待*/int barrier_wait(barrier_t *barrier){ int ret = 0; int cycle; int cancel, tmp; if (barrier->valid != BARRIER_VALID) { return EINVAL; } pthread_mutex_lock(&barrier->mutex); cycle = barrier->cycle; /*barrier->counter不为0则等待,为0则唤醒所有等待的线程*/ if (--barrier->counter == 0) { barrier->cycle++; barrier->counter = barrier->threadshold; ret = pthread_cond_broadcast(&barrier->cond); if (ret == 0) { ret = -1; } } else { /*设置取消状态为DISABLE,因为此处不能成为取消点*/ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel); /*等待*/ while (cycle == barrier->cycle) { pthread_cond_wait(&barrier->cond, &barrier->mutex); } /*恢复原先的取消状态*/ pthread_setcancelstate(cancel, &tmp); } pthread_mutex_unlock(&barrier->mutex); return ret;}
/*barrier_main.c*/#include "barrier.h"#define THREADS 5#define ARRAY 6#define INLOOPS 1000#define OUTLOOPS 10typedef struct thread_tag{ pthread_t thread_id; int number; int increment; int array[ARRAY];}thread_t;barrier_t barrier;thread_t thread[THREADS];void *thread_routine(void *arg){ thread_t *self = (thread_t *)arg; int ret; int count; int in_loop; int out_loop; /*所有线程各自将array里的数据增加*/ for (out_loop = 0; out_loop < OUTLOOPS; out_loop++) { barrier_wait(&barrier); for (in_loop = 0; in_loop < INLOOPS -1 ; in_loop++) { for (count = 0; count < ARRAY; count++) { self->array[count] += self->increment; } } /*"领头线程"即修改*/ ret = barrier_wait(&barrier); if (ret == -1) { int thread_num; for (thread_num = 0; thread_num < THREADS; thread_num++) { thread[thread_num].increment += 1; } } } return NULL;}int main(int argc, char *argv[]){ int thread_count; int array_count; int ret; barrier_init(&barrier, THREADS); /*创建工作队列*/ for (thread_count = 0; thread_count < THREADS; thread_count++) { thread[thread_count].increment = thread_count; thread[thread_count].number = thread_count; for (array_count = 0; array_count < ARRAY; array_count++) { thread[thread_count].array[array_count] = array_count+1; } ret = pthread_create(&thread[thread_count].thread_id, NULL, thread_routine, (void *)&thread[thread_count]); if (ret != 0) { printf("create thread failed : %s\n", strerror(ret)); return -1; } } for (thread_count = 0; thread_count < THREADS; thread_count++) { ret = pthread_join(thread[thread_count].thread_id, NULL); if (ret != 0) { printf("join thread failed : %s\n", strerror(ret)); return -1; } printf("%02d: (%d) ", thread_count, thread[thread_count].increment); for (array_count = 0; array_count < ARRAY; array_count++) { printf("%010u ", thread[thread_count].array[array_count]); } printf("\n"); } barrier_destroy(&barrier); return 0;}
实例2:工作队列
一组线程从同一个工作队列中接受工作请求,并且并行地处理它们。
/*头文件workq.h*/#include <pthread.h>#include <stdlib.h>#include <stdio.h>#include <time.h>#include <errno.h>/*工作队列中的工作元素*/typedef struct workq_ele_tag{ struct workq_ele_tag *next; void *data;}workq_ele_t;/*工作队列*/typedef struct workq_tag{ pthread_mutex_t mutex; pthread_cond_t cond; pthread_attr_t attr; workq_ele_t *first, *last; int valid; int quit; /*退出标志*/ int parallelism;/*允许工作队列使用多少线程*/ int counter; /*记录创建的线程数*/ int idle; /*空闲的线程数*/ void (*engine)(void *arg);/*引擎函数*/}workq_t;#define WORKQ_VALID 0xdec1992extern int workq_init(workq_t *wq, int threads, void (*engine)(void *));extern int workq_destroy(workq_t *wq);extern int workq_add(workq_t *wq, void *data);
/*工作队列workq.c*/ /* *工作队列管理器文件 */#include "workq.h"#include <time.h>/*初始化工作队列*/int workq_init(workq_t *wq, int threads, void (*engine)(void *arg)){ int ret; /*设置线程分离属性*/ pthread_attr_init(&wq->attr); ret = pthread_attr_setdetachstate(&wq->attr, PTHREAD_CREATE_DETACHED); if (ret != 0) { pthread_attr_destroy(&wq->attr); return ret; } pthread_mutex_init(&wq->mutex, NULL); pthread_cond_init(&wq->cond, NULL); wq->quit = 0; wq->first = wq->last = NULL; wq->parallelism = threads; wq->counter = 0; wq->idle = 0; wq->engine = engine; wq->valid = WORKQ_VALID; return 0;}/*销毁工作队列*/int workq_destroy(workq_t *wq){ if (wq->valid != WORKQ_VALID) { return EINVAL; } pthread_mutex_lock(&wq->mutex); wq->valid = 0; if (wq->counter > 0) { wq->quit = 1; if (wq->idle > 0) { pthread_cond_broadcast(&wq->cond); } while (wq->counter > 0) { pthread_cond_wait(&wq->cond, &wq->mutex); } } pthread_mutex_unlock(&wq->mutex); pthread_mutex_destroy(&wq->mutex); pthread_cond_destroy(&wq->cond); pthread_attr_destroy(&wq->attr); return 0;}/*引擎线程的启动函数*/void *workq_server(void *arg){ int ret; int timedout; struct timespec timeout; workq_t *wq = (workq_t *)arg; workq_ele_t *we; pthread_mutex_lock(&wq->mutex); while (1) { timedout = 0; clock_gettime(CLOCK_REALTIME, &timeout); timeout.tv_sec += 2;/*等待2秒*/ while (wq->first == NULL && !wq->quit) { ret = pthread_cond_timedwait(&wq->cond, &wq->mutex, &timeout); if (ret == ETIMEDOUT) { timedout = 1; break; } else if (ret != 0) { wq->counter--; pthread_mutex_unlock(&wq->mutex); return NULL; } } we = wq->first; if (we != NULL) { wq->first = we->next; if (wq->last == we) wq->last = NULL; pthread_mutex_unlock(&wq->mutex); wq->engine(we->data); free(we); pthread_mutex_lock(&wq->mutex); } if (wq->first == NULL && wq->quit) { wq->counter--; if (wq->counter == 0) { pthread_cond_broadcast(&wq->cond); } pthread_mutex_unlock(&wq->mutex); return NULL; } if (wq->first == NULL && timedout) { wq->counter--; break; } } pthread_mutex_unlock(&wq->mutex); return NULL;}/*添加工作元素到工作队列*/int workq_add(workq_t *wq, void *element){ workq_ele_t *item; pthread_t id; int ret; if (wq->valid != WORKQ_VALID) { return EINVAL; } item = (workq_ele_t *)malloc(sizeof(workq_ele_t)); if (item == NULL) { printf("malloc failed ...\n"); return ENOMEM; } item->data = element; item->next = NULL; pthread_mutex_lock(&wq->mutex); /*添加工作元素item到链表first的尾部*/ if (wq->first == NULL) wq->first = item; else wq->last->next = item; wq->last = item; /*如果有空闲的引擎线程,则唤醒其中一个*/ if (wq->idle > 0) { pthread_cond_signal(&wq->cond); } /*创建新的引擎线程*/ else if (wq->counter < wq->parallelism) { ret = pthread_create(&id, &wq->attr, workq_server, (void *)wq); if (ret != 0) { pthread_mutex_unlock(&wq->mutex); printf("create thread failed ...\n"); return ret; } wq->counter++; } pthread_mutex_unlock(&wq->mutex); return 0;}
/*workq_main.c*/#include "workq.h"#define ITERATIONS 25typedef struct power_tag{ int value; int power;}power_t;typedef struct engine_tag{ struct engine_tag *link; pthread_t thread_id; int calls;}engine_t;pthread_key_t engine_key;pthread_mutex_t engine_list_mutex = PTHREAD_MUTEX_INITIALIZER;engine_t *engine_list_head = NULL;workq_t workq;/*引擎线程退出时,销毁私有存储数据*/void destructor(void *value_ptr){ engine_t *engine = (engine_t *)value_ptr; pthread_mutex_lock(&engine_list_mutex); engine->link = engine_list_head; engine_list_head = engine; pthread_mutex_unlock(&engine_list_mutex);}void engine_routine(void *arg){ int result; int count; engine_t *engine; power_t *power = (power_t *)arg; engine = pthread_getspecific(engine_key); if (engine == NULL) { engine = (engine_t *)malloc(sizeof(engine_t)); pthread_setspecific(engine_key, (void *)engine); engine->thread_id = pthread_self(); engine->calls = 1; } else { engine->calls++; } result = 1; printf("engine: computing %d^%d\n", power->value, power->power); for (count = 1; count <= power->power; count++) result *= power->value; free(arg);}void *thread_routine(void *arg){ int ret; int count; power_t *element; unsigned int seed = (unsigned int)time(NULL); for (count = 0; count < ITERATIONS; count++) { element = (power_t *)malloc(sizeof(power_t)); if (element == NULL) { printf("malloc failed ...\n"); return NULL; } element->value = rand_r(&seed) % 20; element->power = rand_r(&seed) % 7; ret = workq_add(&workq, (void *)element); if(ret != 0) { printf("add to work queue failed...\n"); return NULL; } sleep(rand_r(&seed) % 5); } return NULL;}int main(int argc, char *argv[]){ int ret; engine_t *engine; pthread_t thread_id; int count = 0, calls = 0; ret = pthread_key_create(&engine_key, destructor); if (ret != 0) { printf("create thread key failed: %s\n", strerror(ret)); return -1; } /*初始化工作队列*/ workq_init(&workq, 4, engine_routine); /*主线程和子线程并行地向工作队列添加工作元素*/ /*创建子线程向工作队列添加工作元素*/ ret = pthread_create(&thread_id, NULL, thread_routine, NULL); if (ret != 0) { printf("create thread failed: %s\n", strerror(ret)); return -1; } /*主线程向工作队列添加工作元素*/ thread_routine(NULL); /*销毁工作队列*/ workq_destroy(&workq); engine = engine_list_head; while (engine != NULL) { count++; calls += engine->calls; printf("engine %d: %d calls\n", count, engine->calls); engine = engine->link; } printf("%d engine threads processd %d calls\n", count, calls); return 0;}
输出:
[root]# gcc workq.c workq_main.c -lrt -pthread[root]# ./a.out engine: computing 9^0engine: computing 9^0engine: computing 17^2engine: computing 17^2engine: computing 3^3engine: computing 3^3engine: computing 6^3engine: computing 6^3engine: computing 16^2engine: computing 16^5engine: computing 16^2engine: computing 16^5engine: computing 0^5engine: computing 9^3engine: computing 0^5engine: computing 9^3engine: computing 0^3engine: computing 0^1engine: computing 9^6engine: computing 0^3engine: computing 0^1engine: computing 9^6engine: computing 15^4engine: computing 15^4engine: computing 8^3engine: computing 12^6engine: computing 8^3engine: computing 12^6engine: computing 17^2engine: computing 17^2engine: computing 13^6engine: computing 13^6engine: computing 2^3engine: computing 2^3engine: computing 7^6engine: computing 8^6engine: computing 18^5engine: computing 7^6engine: computing 8^6engine: computing 18^5engine: computing 10^5engine: computing 10^5engine: computing 10^1engine: computing 10^1engine: computing 6^2engine: computing 6^2engine: computing 7^6engine: computing 7^6engine: computing 14^1engine: computing 14^1engine 1: 2 callsengine 2: 2 callsengine 3: 1 callsengine 4: 2 callsengine 5: 1 callsengine 6: 5 callsengine 7: 5 callsengine 8: 1 callsengine 9: 1 callsengine 10: 1 callsengine 11: 1 callsengine 12: 2 callsengine 13: 2 callsengine 14: 1 callsengine 15: 1 callsengine 16: 3 callsengine 17: 3 callsengine 18: 2 callsengine 19: 2 callsengine 20: 3 callsengine 21: 2 callsengine 22: 1 callsengine 23: 1 callsengine 24: 1 callsengine 25: 1 callsengine 26: 3 calls26 engine threads processd 50 calls[root]#
0 0
- POSIX多线程程序设计(第7章:Real code)
- POSIX多线程程序设计(第1章:概述)
- POSIX多线程程序设计(第2章:线程)
- POSIX多线程程序设计(第3章:同步)
- POSIX多线程程序设计(第5章:线程高级编程)
- POSIX多线程程序设计(第6章:POSIX针对线程的调整)
- POSIX多线程程序设计(第4章:使用线程的几种方式)
- POSIX多线程程序设计(第8章:避免调试的提示)
- Linux程序设计笔记(第12章 POSIX线程)
- Programming With POSIX Threads(POSIX多线程程序设计)
- POSIX 多线程程序设计
- POSIX 多线程程序设计
- Pthread:POSIX 多线程程序设计
- POSIX 多线程程序设计
- POSIX 多线程程序设计
- Pthread:POSIX 多线程程序设计
- POSIX 多线程程序设计
- POSIX 多线程程序设计
- Android Studio NDK 学习之接受Java传入的Int数组
- C++中类对象所占空间的大小
- 执行mvn 报错 source-1.5 中不支持
- Kth Smallest Element in a BST
- 华为OJ 名字的漂亮度
- POSIX多线程程序设计(第7章:Real code)
- AngularJs中Factory和Service和Provide不同(写得很好)
- Excel VBA编程的常用代码(备用待查)
- QT 学习遇到的问题记录2—qml 调用qt c++
- SQLite3查询表结构
- 观察者——对象行为模式
- java socket编程学习笔记
- POSIX多线程程序设计(第8章:避免调试的提示)
- Windows 系统下设置Nodejs NPM全局路径