我的测试环境是CentOS7(内核版本3.10.0),X86_64.
头文件: wrlock.h
#ifndef _WRLOCK_H
#define _WRLOCK_H
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
struct job {
struct job *j_next;
struct job *j_prev;
pthread_t tid;
void *( *job_func)( void *);
};
struct queue {
struct job *q_head;
struct job *q_tail;
pthread_rwlock_t q_lock;
};
int queue_init( struct queue *qp );
void job_insert( struct queue *qp, struct job *jp );
void job_append( struct queue *qp, struct job *jp );
void job_remove( struct queue *qp, struct job *jp );
struct job *job_find( struct queue *qp, pthread_t tid );
#endif
队列的相关操作,这一部分与书上的基本一样。
11_14.c
#include "wrlock.h"
int
queue_init( struct queue *qp )
{
int err;
qp->q_head = qp->q_tail = NULL;
if ((err = pthread_rwlock_init(&qp->q_lock,NULL)) != 0)
return err;
return 0;
}
/* insert a job at the head of queue */
void
job_insert( struct queue *qp, struct job *jp )
{
pthread_rwlock_wrlock(&qp->q_lock);
jp->j_next = qp->q_head;
jp->j_prev = NULL;
if ( qp->q_head != NULL )
qp->q_head->j_prev = jp;
else
qp->q_tail = jp;
qp->q_head = jp;
pthread_rwlock_unlock(&qp->q_lock);
}
/* append a job on the tail of queue */
void
job_append( struct queue *qp, struct job *jp )
{
pthread_rwlock_wrlock(&qp->q_lock);
jp->j_next = NULL;
jp->j_prev = qp->q_tail;
if ( qp->q_tail != NULL )
qp->q_tail->j_next = jp;
else
qp->q_head = jp;
qp->q_tail = jp;
pthread_rwlock_unlock(&qp->q_lock);
}
void
job_remove( struct queue *qp, struct job *jp )
{
pthread_rwlock_wrlock(&qp->q_lock);
/*
** remove the head job,maybe jp pointing the only job.
*/
if (jp == qp->q_head){
qp->q_head = jp->j_next;
if (jp->j_next != NULL)
jp->j_next->j_prev = NULL;
else
qp->q_tail = NULL;
} /*
** remove the tail job, if jp pointing the only job,
** then if{} statements has executed, we can't get here.
*/
else if ( jp == qp->q_tail ){
qp->q_tail = jp->j_prev;
jp->j_prev->j_next = NULL;
} else{
jp->j_next->j_prev = jp->j_prev;
jp->j_prev->j_next = jp->j_next;
}
pthread_rwlock_unlock(&qp->q_lock);
}
struct job *
job_find( struct queue *qp, pthread_t tid )
{
struct job *jtmp;
if(pthread_rwlock_rdlock(&qp->q_lock) != 0)
return NULL;
for ( jtmp = qp->q_head; jtmp != NULL; jtmp = jtmp->j_next ){
if (pthread_equal(jtmp->tid,tid) != 0)
break;
}
pthread_rwlock_unlock(&qp->q_lock);
return jtmp;
}
main函数部分,主线程负责初始化队列,将产生的job插入队列,job结构中有指派的线程的id,以及给出的任务(函数指针)。其他的工作线程从队列中找到属于自己的job,然后利用这个函数指针调用函数,完成任务。任务很简单,就是打印一句话。
main.c:
#include "wrlock.h"
#define _GNU_SOURCE
void *
task1( void *str1 )
{
printf("I am thread 1, %s\n",(char *)str1);
}
void *
task2( void *str2 )
{
printf("I am thread 2, %s\n",(char *)str2);
}
void *
task3( void *str3 )
{
printf("I am thread 3, %s\n",(char *)str3);
}
void *
thr1_func( void *arg ) //arg points to queue.
{
pthread_t tid;
struct job *jp1;
tid = pthread_self();
while (1){
if ((jp1 = job_find(arg,tid)) != NULL){
jp1->job_func("task completly!");
job_remove(arg,jp1);
free(jp1);
}else{
pthread_yield();
}
}
}
void *
thr2_func( void *arg ) //arg points to queue.
{
pthread_t tid;
struct job *jp2;
tid = pthread_self();
while (1){
if ((jp2 = job_find(arg,tid)) != NULL){
jp2->job_func("task completly!");
job_remove(arg,jp2);
free(jp2);
}else{
pthread_yield();
}
}
}
void *
thr3_func( void *arg ) //arg points to queue.
{
pthread_t tid;
struct job *jp3;
tid = pthread_self();
while (1){
if ((jp3 = job_find(arg,tid)) != NULL){
jp3->job_func("task completly!");
job_remove(arg,jp3);
free(jp3);
}else{
pthread_yield();
}
}
}
int
main( void )
{
unsigned long n;
int err;
int foo;
struct job *jobptr;
struct queue *qptr;
pthread_t tid[3];
void *(*func[3])(void *) = { task1, task2, task3 };
/* initialise the queue */
if ((qptr = malloc(sizeof( struct queue ))) == NULL)
exit(-1);
queue_init(qptr);
/* produce task in main thread */
err = pthread_create(&tid[0],NULL,thr1_func,qptr);
if (err != 0)
exit(-1);
else
printf("create thread 1 success\n");
err = pthread_create(&tid[1],NULL,thr2_func,qptr);
if (err != 0)
exit(-1);
else
printf("create thread 2 success\n");
err = pthread_create(&tid[2],NULL,thr3_func,qptr);
if (err != 0)
exit(-1);
else
printf("create thread 3 success\n");
for ( n = 1; n <= 10; n++){
if ((jobptr = malloc(sizeof(struct job))) == NULL)
exit(-1);
foo = rand()%3;
jobptr->tid = tid[foo];
jobptr->job_func = func[foo];
job_insert(qptr,jobptr);
}
sleep(10);
exit(0);
}