Chinaunix首页 | 论坛 | 博客
  • 博客访问: 751697
  • 博文数量: 130
  • 博客积分: 2951
  • 博客等级: 少校
  • 技术积分: 1875
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-04 18:32
文章分类

全部博文(130)

文章存档

2013年(1)

2012年(129)

分类: C/C++

2012-11-01 11:51:02

这个程序的作用是统计输入的两个文件的字数,使用方法
./program cp1.c cp2.c
  1. /* threaded word counter for two files.    
  2.  */

  3. #include <stdio.h>
  4. #include <pthread.h>
  5. #include <ctype.h>

  6. struct arg_set {       
  7.         char *fname;    //文件名
  8.         int count;    //文字数量
  9.         char *name;   //线程名字
  10. };

  11. struct arg_set *mailbox = NULL;
  12. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  13. pthread_cond_t flag = PTHREAD_COND_INITIALIZER;

  14. main(int ac, char *av[])
  15. {
  16.     pthread_t t1, t2;        /* two threads */
  17.     struct arg_set args1, args2;    /* two argsets */
  18.     void     *count_words(void *);
  19.     int reports_in = 0;
  20.     int     total_words = 0;

  21.     if ( ac != 3 ){
  22.         printf("usage: %s file1 file2\n", av[0]);
  23.         exit(1);
  24.     }
  25.     pthread_mutex_lock(&lock);    // 对互斥量加锁

  26.     args1.fname = av[1];
  27.     args1.count = 0;
  28.     args1.name = "1";
  29.     pthread_create(&t1, NULL, count_words, (void *) &args1); //开启第一个线程

  30.     args2.fname = av[2];
  31.     args2.count = 0;
  32.     args2.name = "2";
  33.     pthread_create(&t2, NULL, count_words, (void *) &args2); //开启第二个线程
  34.     
  35.     /* sleep(10); */ //这里通过sleep函数来检查一下对同一个lock加锁多次的现象,
  36.                      //在本人的机器上,主线程sleep的时候,
  37.                      //子线程们会pending在线程函数对互斥量加锁的地方;也就是count_words中的第17行的地方。
  38.     while( reports_in < 2 ){
  39.         printf("MAIN: waiting for flag to go up\n");
  40.         pthread_cond_wait(&flag, &lock); //pthread_cond_wait的作用是
  41.                                          //1.先释放锁
  42.                                          //2.等待信号flag的变化
  43.                                          //3.当收到信号变更通知的时候被唤醒,再次对互斥量加锁
  44.         printf("MAIN: Wow! flag was raised, I have the lock\n");
  45.         printf("%7d: %s\n", mailbox->count, mailbox->fname);
  46.         total_words += mailbox->count;
  47.         if ( mailbox == &args1)
  48.             pthread_join(t1,NULL);
  49.         if ( mailbox == &args2)
  50.             pthread_join(t2,NULL);
  51.         mailbox = NULL;
  52.         pthread_cond_signal(&flag);        // 告知信号有变化,如果没有线程在等待信号变化,
  53.                                            //那么不会发生什么,如果有线程在等待信号,那么该线程被唤醒
  54.         reports_in++;
  55.     }
  56.     printf("%7d: total words\n", total_words);
  57. }
  58. void *count_words(void *a)
  59. {
  60.     struct arg_set *args = a;    /* cast arg back to correct type */
  61.     FILE *fp;
  62.     int c, prevc = '\0';
  63.     
  64.     if ( (fp = fopen(args->fname, "r")) != NULL ){
  65.         while( ( c = getc(fp)) != EOF ){
  66.             if ( !isalnum(c) && isalnum(prevc) )
  67.                 args->count++;
  68.             prevc = c;
  69.         }
  70.         fclose(fp);
  71.     } else
  72.         perror(args->fname);
  73.     printf("COUNT%s: waiting to get lock\n", args->name);
  74.     pthread_mutex_lock(&lock);    //子线程对互斥量加锁
  75.     printf("COUNT%s: have lock, storing data\n", args->name);

  76.     if ( mailbox != NULL ){ //如果mailbox不为空,这种情况出现在第一个子线程结束后,
  77.                             //第二个子线程马上获得锁,并开始执行,
  78.                              //而主线程此时虽然已经获得信号变化通知,
  79.                              //但是被其它子线程抢先对互斥量加锁并执行。
  80.                              //这样主线程的pthread_cond_wait(&flag, &lock);就无法对互斥量加锁,
  81.                              //pthread_cond_wait(&flag, &lock);函数不能返回,继续等待。
  82.         printf("COUNT%s: oops..mailbox not empty. wait for signal\n", args->name);
  83.         pthread_cond_wait(&flag,&lock); //而当第二个子线程执行到这里发现mailbox不为空的时候,它执行                                                 //pthread_cond_wait(&flag, &lock);函数,
  84.                                         //这个函数首先释放锁,并等待信号变化
  85.                                         //此时,主线程的pthread_cond_wait(&flag, &lock);才能对互斥量加锁,
  86.                                         //从而返回,继续执行。
  87.                                         //而这里第二个子线程将等待主线程pthread_cond_signal(&flag);
  88.                                         //函数的执行,从而获取信号变化通知,
  89.                                         //然后主线程的while循环到再次执行pthread_cond_wait(&flag, &lock);
  90.                                         //的时候,主线程释放了锁,子线程才能对互斥量继续加锁,从而继续执行。
  91.     }
  92.     mailbox = args;            /* put ptr to our args there */
  93.     printf("COUNT%s: raising flag\n", args->name);
  94.     pthread_cond_signal(&flag);                //通知主线程信号变化
  95.     printf("COUNT%s: unlocking box\n", args->name);
  96.     pthread_mutex_unlock(&lock);                //释放锁。
  97.     printf("COUNT%s: unlocked box\n", args->name);
  98.     return NULL;
  99. }
输出:

  1. [lizhuohua@lizhuohua-phy Program]$ ./program cp1.c cp2.c
  2. COUNT1: waiting to get lock
  3. COUNT2: waiting to get lock
  4. MAIN: waiting for flag to go up
  5. COUNT1: have lock, storing data
  6. COUNT1: raising flag
  7. COUNT1: unlocking box
  8. COUNT1: unlocked box
  9. MAIN: flag was raised, I have the lock
  10.     131: cp1.c
  11. MAIN: waiting for flag to go up
  12. COUNT2: have lock, storing data
  13. COUNT2: raising flag
  14. COUNT2: unlocking box
  15. COUNT2: unlocked box
  16. MAIN: flag was raised, I have the lock
  17.     131: cp2.c
  18.     262: total words

总结一下这个程序可能的执行过程:
1. 第一种
a 主线程create两个子线程后,进入到pthread_cond_wait阻塞,释放锁,等待信号
b 第一个子线程,对文件中的word计数,对互斥量加锁,
c 第二个子线程,对文件中的word计数,在pthead_mutex_lock处阻塞
d 第一个子线程,给mailbox赋值,通知信号变化,释放锁,退出, 主线程获得信号通知
e 第二个子线程,抢先主线程对互斥量加锁,判断mailbox不为NULL,释放锁,并等待信号
f 主线程对互斥量加锁,从pthread_cond_wait返回,清空mailbox,通知信号变化,并在再次循环中pthread_cond_wait释放锁,等待信号
g 第二个子线程,获得信号通知,加锁,继续执行,通知信号, 释放锁
h 主线程获得信号,加锁,继续执行,然后执行pthread_cond_signal时候已经没有线程等待。

2. 第二种
a 主线程create两个子线程后,进入到pthread_cond_wait阻塞,释放锁,等待信号
b 第一个子线程,对文件中的word计数,对互斥量加锁,
c 第二个子线程,对文件中的word计数,在pthead_mutex_lock处阻塞
d 第一个子线程,给mailbox赋值,通知信号变化,释放锁,退出, 主线程获得信号通知
e 主线程对互斥量加锁,从pthread_cond_wait返回,清空mailbox,通知信号变化,并在再次循环中pthread_cond_wait释放锁,等待信号
f 第二个子线程,对互斥量加锁,给mailbox赋值,通知信号变化,释放锁,退出, 主线程获得信号通知
g 主线程获得信号,加锁,继续执行,然后执行pthread_cond_signal时候已经没有线程等待。


问题:
分析到最后,我发现这个主线程最后退出的时候,都没有把最后一次pthread_cond_wait中加锁的互斥量解锁。
这样不解锁就退出,会有什么后果呢?

阅读(4009) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~