实例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 10
typedef 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 0xdec1992
extern 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 25
typedef 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^0
engine: computing 9^0
engine: computing 17^2
engine: computing 17^2
engine: computing 3^3
engine: computing 3^3
engine: computing 6^3
engine: computing 6^3
engine: computing 16^2
engine: computing 16^5
engine: computing 16^2
engine: computing 16^5
engine: computing 0^5
engine: computing 9^3
engine: computing 0^5
engine: computing 9^3
engine: computing 0^3
engine: computing 0^1
engine: computing 9^6
engine: computing 0^3
engine: computing 0^1
engine: computing 9^6
engine: computing 15^4
engine: computing 15^4
engine: computing 8^3
engine: computing 12^6
engine: computing 8^3
engine: computing 12^6
engine: computing 17^2
engine: computing 17^2
engine: computing 13^6
engine: computing 13^6
engine: computing 2^3
engine: computing 2^3
engine: computing 7^6
engine: computing 8^6
engine: computing 18^5
engine: computing 7^6
engine: computing 8^6
engine: computing 18^5
engine: computing 10^5
engine: computing 10^5
engine: computing 10^1
engine: computing 10^1
engine: computing 6^2
engine: computing 6^2
engine: computing 7^6
engine: computing 7^6
engine: computing 14^1
engine: computing 14^1
engine 1: 2 calls
engine 2: 2 calls
engine 3: 1 calls
engine 4: 2 calls
engine 5: 1 calls
engine 6: 5 calls
engine 7: 5 calls
engine 8: 1 calls
engine 9: 1 calls
engine 10: 1 calls
engine 11: 1 calls
engine 12: 2 calls
engine 13: 2 calls
engine 14: 1 calls
engine 15: 1 calls
engine 16: 3 calls
engine 17: 3 calls
engine 18: 2 calls
engine 19: 2 calls
engine 20: 3 calls
engine 21: 2 calls
engine 22: 1 calls
engine 23: 1 calls
engine 24: 1 calls
engine 25: 1 calls
engine 26: 3 calls
26 engine threads processd 50 calls
[root]#