在linux C程序设计大全这本书里,讲到了线程的高级编程。这本书讲的挺细,但是程序错误较多。第一个关于互斥量使用的演示程序就有很多错误,不过我按照作者的思路,把程序修改了下。这个程序的主要内容是在main函数里构建一个链表,两个线程分别操作这个链表,从中取出链表的3个节点。注意,这两个线程在各取完自己的节点,只剩下一个头指针了。这里就需要互斥操作,完整程序代码如下:
-
#include <stdio.h>
-
#include <pthread.h>
-
#include <string.h>
-
#include <stdlib.h>
-
#define MAX_ITEM 3 //每次最多取三个任务
-
-
typedef struct job{
-
pthread_t tid;
-
struct job *next; //下一个链表节点
-
int val; //节点值
-
}Job;
-
-
pthread_mutex_t q_lock = PTHREAD_MUTEX_INITIALIZER;//全局变量锁
-
-
int insert(Job **head, int val, pthread_t tid)
-
{
-
Job *p,*q;
-
p = *head; //头指针 不存放实际东西
-
-
if(p != NULL)//p一定不为NULL
-
{
-
while(p->next != NULL)
-
{
-
p = p->next;
-
}
-
}
-
-
q = (Job *)malloc(sizeof(Job));
-
if(q == NULL)
-
{
-
perror("fail to malloc");
-
return -1;
-
}
-
q->next = NULL;
-
q->val = val;
-
q->tid = tid;//设置节点的所有者,线程1
-
//p->next = q; //将节点链入任务队列
-
-
if(p == NULL)//可以省掉
-
{
-
*head = q;
-
return 0;
-
}
-
-
p->next = q;//插入到队列中
-
return 0;
-
}
-
-
void get_job(Job *head, Job **task, int *count, pthread_t tid)//tid 线程的
-
{
-
Job *p, *q;
-
q = head; //参数是任务队列头
-
p = q->next;
-
-
while(p != NULL)
-
{
-
if(tid == p->tid)//找到属于当前线程的任务节点
-
{
-
q->next = p->next;//将该节点从原始节点任务中去掉
-
p->next = *task;//task一开始NULL
-
*task = p;//从前往后插入链表,当前节点作为本线程任务头节点
-
p = q->next;//继续沿原任务节点找
-
(*count)++;
-
}//这里面的赋值会改变原始item的链表
-
else
-
{
-
q = p;
-
p = p->next;
-
}
-
}
-
}
-
-
void free_job(Job *head)
-
{
-
Job *p, *q;
-
for(p = head; p != NULL; )
-
{
-
q = p;
-
p = p->next;
-
free(q);
-
//printf("u\n");//测试用的
-
}
-
}
-
-
void print(Job *task)
-
{
-
Job *p;
-
for(p = task; p != NULL; p = p->next)
-
printf("thread %u: %d\n",p->tid,p->val);
-
}
-
-
void *thfn(void *arg)
-
{
-
int count;
-
Job *task = NULL;//线程任务头节点
-
pthread_t tid;
-
-
tid = pthread_self();//得到当前线程ID
-
-
count = 0;
-
while(count < MAX_ITEM)
-
{
-
if(pthread_mutex_trylock(&q_lock) == 0)//将队列加锁
-
{
-
get_job((Job *)arg,&task,&count,tid);//使用&task来改变task
-
pthread_mutex_unlock(&q_lock);//释放锁
-
}
-
}
-
print(task);
-
-
free_job(task);
-
printf("===OK\n");
-
return (void *)0;
-
}
-
-
int main(void)
-
{
-
Job *item;
-
pthread_t tid1,tid2;
-
int i;
-
int err;
-
-
item = (Job *)malloc(sizeof(Job)); //设置头节点,该节点不存储有效信息
-
item->next = NULL;
-
item->val = 0;
-
item->tid = -1;
-
-
/*创建2个线程,这2个线程会根据自己的线程ID
-
取走不同的任务节点*/
-
err = pthread_create(&tid1, NULL, thfn, (void *)item);//创建第一个线程
-
if(err != 0)
-
{
-
printf("fail to create thread %s\n",strerror(err));
-
exit(1);
-
}
-
-
err = pthread_create(&tid2, NULL, thfn, (void *)item);//创建第二个线程
-
if(err != 0)
-
{
-
printf("fail to create thread %s\n",strerror(err));
-
exit(1);
-
}
-
-
printf("===the 1st put===\n");
-
pthread_mutex_lock(&q_lock);//锁住任务队列
-
for(i=0; i<2; i++)//共执行两次,每次放入2个节点,分别属于不同线程
-
{
-
if(insert(&item,i,tid1) == -1)
-
exit(1);
-
if(insert(&item,i+1,tid2) == -1)
-
exit(1);
-
}
-
if(insert(&item,10,tid1) == -1)//给tid1加第三个任务节点
-
exit(1);
-
-
pthread_mutex_unlock(&q_lock);//释放锁,当前任务队列中共5个任务
-
//3个属于线程1,2个属于线程2
-
sleep(5);
-
/*休眠*/
-
-
print(item);/*这里输出的结果是item头,验证了get_job对其链表的改变*/
-
-
printf("===the 2nd put===\n");//第二次输入,给线程2再加一个任务
-
-
pthread_mutex_lock(&q_lock);
-
if(insert(&item, 9, tid2) == -1)
-
exit(1);
-
pthread_mutex_unlock(&q_lock);//释放锁
-
-
/*这个时候可以使用pthread_join函数了*/
-
err = pthread_join(tid1,NULL);
-
if(err != 0)
-
{
-
printf("can't join thread %s\n",strerror(err));
-
exit(1);
-
}
-
err = pthread_join(tid2,NULL);
-
if(err != 0)
-
{
-
printf("can't join thread %s\n",strerror(err));
-
exit(1);
-
}
-
-
printf("main thread done\n");
-
if(item->next == NULL)
-
printf("no job in the queue\n");
-
free(item);
-
return 0;
-
}
程序里需要注意的是,通过函数改变指针的值时,要把指针的地址作为参数传入。另外一个难点就是链表的操作了,不明白的就看看数据结构吧,不难。
阅读(112) | 评论(0) | 转发(0) |