Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1406
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 20
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-15 16:56
文章分类
文章存档

2015年(1)

我的朋友
最近访客

分类: LINUX

2015-06-03 18:19:37

在linux C程序设计大全这本书里,讲到了线程的高级编程。这本书讲的挺细,但是程序错误较多。第一个关于互斥量使用的演示程序就有很多错误,不过我按照作者的思路,把程序修改了下。这个程序的主要内容是在main函数里构建一个链表,两个线程分别操作这个链表,从中取出链表的3个节点。注意,这两个线程在各取完自己的节点,只剩下一个头指针了。这里就需要互斥操作,完整程序代码如下:


点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #define MAX_ITEM 3 //每次最多取三个任务

  6. typedef struct job{
  7.     pthread_t tid;
  8.     struct job *next; //下一个链表节点
  9.     int val; //节点值
  10. }Job;

  11. pthread_mutex_t q_lock = PTHREAD_MUTEX_INITIALIZER;//全局变量锁

  12. int insert(Job **head, int val, pthread_t tid)
  13. {
  14.     Job *p,*q;
  15.     p = *head; //头指针 不存放实际东西

  16.     if(p != NULL)//p一定不为NULL
  17.     {
  18.         while(p->next != NULL)
  19.         {
  20.             p = p->next;
  21.         }
  22.     }

  23.     q = (Job *)malloc(sizeof(Job));
  24.     if(q == NULL)
  25.     {
  26.         perror("fail to malloc");
  27.         return -1;
  28.     }
  29.     q->next = NULL;
  30.     q->val = val;
  31.     q->tid = tid;//设置节点的所有者,线程1
  32.     //p->next = q; //将节点链入任务队列

  33.     if(p == NULL)//可以省掉
  34.     {
  35.         *head = q;
  36.         return 0;
  37.     }

  38.     p->next = q;//插入到队列中
  39.     return 0;
  40. }

  41. void get_job(Job *head, Job **task, int *count, pthread_t tid)//tid 线程的
  42. {
  43.     Job *p, *q;
  44.     q = head; //参数是任务队列头
  45.     p = q->next;

  46.     while(p != NULL)
  47.     {
  48.         if(tid == p->tid)//找到属于当前线程的任务节点
  49.         {
  50.             q->next = p->next;//将该节点从原始节点任务中去掉
  51.             p->next = *task;//task一开始NULL
  52.             *task = p;//从前往后插入链表,当前节点作为本线程任务头节点
  53.             p = q->next;//继续沿原任务节点找
  54.             (*count)++;
  55.         }//这里面的赋值会改变原始item的链表
  56.         else
  57.         {
  58.             q = p;
  59.             p = p->next;
  60.         }
  61.     }
  62. }

  63. void free_job(Job *head)
  64. {
  65.     Job *p, *q;
  66.     for(p = head; p != NULL; )
  67.     {
  68.         q = p;
  69.         p = p->next;
  70.         free(q);
  71.         //printf("u\n");//测试用的
  72.     }
  73. }

  74. void print(Job *task)
  75. {
  76.     Job *p;
  77.     for(p = task; p != NULL; p = p->next)
  78.         printf("thread %u: %d\n",p->tid,p->val);
  79. }

  80. void *thfn(void *arg)
  81. {
  82.     int count;
  83.     Job *task = NULL;//线程任务头节点
  84.     pthread_t tid;

  85.     tid = pthread_self();//得到当前线程ID

  86.     count = 0;
  87.     while(count < MAX_ITEM)
  88.     {
  89.         if(pthread_mutex_trylock(&q_lock) == 0)//将队列加锁
  90.         {
  91.             get_job((Job *)arg,&task,&count,tid);//使用&task来改变task
  92.             pthread_mutex_unlock(&q_lock);//释放锁
  93.         }
  94.     }
  95.     print(task);

  96.     free_job(task);
  97.     printf("===OK\n");
  98.     return (void *)0;
  99. }

  100. int main(void)
  101. {
  102.     Job *item;
  103.     pthread_t tid1,tid2;
  104.     int i;
  105.     int err;

  106.     item = (Job *)malloc(sizeof(Job)); //设置头节点,该节点不存储有效信息
  107.     item->next = NULL;
  108.     item->val = 0;
  109.     item->tid = -1;

  110.     /*创建2个线程,这2个线程会根据自己的线程ID
  111.      取走不同的任务节点*/
  112.     err = pthread_create(&tid1, NULL, thfn, (void *)item);//创建第一个线程
  113.     if(err != 0)
  114.     {
  115.         printf("fail to create thread %s\n",strerror(err));
  116.         exit(1);
  117.     }

  118.     err = pthread_create(&tid2, NULL, thfn, (void *)item);//创建第二个线程
  119.     if(err != 0)
  120.     {
  121.         printf("fail to create thread %s\n",strerror(err));
  122.         exit(1);
  123.     }

  124.     printf("===the 1st put===\n");
  125.     pthread_mutex_lock(&q_lock);//锁住任务队列
  126.     for(i=0; i<2; i++)//共执行两次,每次放入2个节点,分别属于不同线程
  127.     {
  128.         if(insert(&item,i,tid1) == -1)
  129.             exit(1);
  130.         if(insert(&item,i+1,tid2) == -1)
  131.             exit(1);
  132.     }
  133.     if(insert(&item,10,tid1) == -1)//给tid1加第三个任务节点
  134.         exit(1);

  135.     pthread_mutex_unlock(&q_lock);//释放锁,当前任务队列中共5个任务
  136.      //3个属于线程1,2个属于线程2
  137.     sleep(5);
  138.     /*休眠*/

  139.     print(item);/*这里输出的结果是item头,验证了get_job对其链表的改变*/

  140.     printf("===the 2nd put===\n");//第二次输入,给线程2再加一个任务

  141.     pthread_mutex_lock(&q_lock);
  142.     if(insert(&item, 9, tid2) == -1)
  143.         exit(1);
  144.     pthread_mutex_unlock(&q_lock);//释放锁

  145.     /*这个时候可以使用pthread_join函数了*/
  146.     err = pthread_join(tid1,NULL);
  147.     if(err != 0)
  148.     {
  149.         printf("can't join thread %s\n",strerror(err));
  150.         exit(1);
  151.     }
  152.     err = pthread_join(tid2,NULL);
  153.     if(err != 0)
  154.     {
  155.         printf("can't join thread %s\n",strerror(err));
  156.         exit(1);
  157.     }

  158.     printf("main thread done\n");
  159.     if(item->next == NULL)
  160.         printf("no job in the queue\n");
  161.     free(item);
  162.     return 0;
  163. }

程序里需要注意的是,通过函数改变指针的值时,要把指针的地址作为参数传入。另外一个难点就是链表的操作了,不明白的就看看数据结构吧,不难。

阅读(112) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~