多线程编程---条件变量的逻辑分析

         最近学习多线程编程,感觉代码的逻辑运行机理(也即是多个线程的切换、调用机理)是多线程编程需要注意的。

先看下面的例程:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex; /* 定义互斥量 */
int x; /* 定义全局变量 */
void thread1(void) /* 定义线程1运行的函数,其功能是对全局变量x进行逐减操作 */
{
  while(x>0)
  {
    pthread_mutex_lock(&mutex); /* 对互斥量进行加锁操作 */
    printf("Thread 1 is running : x=%d \n",x);
    x--;
    pthread_mutex_unlock(&mutex); /* 对互斥量进行解锁操作 */
    sleep(1);
  }
  pthread_exit(NULL);
}
void thread2(void) /* 定义线程2运行的函数,功能与thread2相同 */
{
  while(x>0)
  {
    pthread_mutex_lock(&mutex); /* 对互斥量进行加锁操作 */
    printf("Thread 2 is running : x=%d \n",x);
    x--;
    pthread_mutex_unlock(&mutex); /* 对互斥量进行解锁操作 */
    sleep(1);
  }
  pthread_exit(NULL);
}
int main(void)
{
  pthread_t id1,id2; /* 定义线程的标识符 */
  int ret;
  ret = pthread_mutex_init(&mutex,NULL); /* 对互斥量进行初始化,这里使用默认的属性 */
  if(ret != 0)
  {
    printf ("Mutex initialization failed.\n"); /* 如果初始化失败,打印错误信息 */
    exit (1);
  }
  x=10; /* 对全局变量赋初值 */
  ret = pthread_create(&id1, NULL, (void *)&thread1, NULL);/* 创建线程1 */
  if(ret != 0)
  {
    printf ("Thread1 creation failed.\n");
    exit (1);
  }
  ret = pthread_create(&id2, NULL, (void *)&thread2, NULL);/* 创建线程2 */
  if(ret != 0)
  {
    printf ("Thread2 creation failed.\n");
    exit (1);
  }
  pthread_join(id1, NULL); /*线程合并 */
  pthread_join(id2, NULL);
  return (0);
}

上述例程只是运用简单的互斥量,实现了两个不同进程间的切换运行。

再看下面的例程:

#include <stdio.h>#include <stdlib.h>#include <pthread.h>pthread_mutex_t mutex; /* 定义互斥量 */pthread_cond_t cond; /* 定义条件变量 */int x; /* 定义全局变量 */void producer(void) /* 定义生产者线程运行的函数,其功能是对全局变量x进行逐加操作 */{  while(1)  {    pthread_mutex_lock(&mutex); /* 对互斥量进行加锁操作 */    int i;    for(i=0;i<3-x;i++) /* 当x的值小于3时,进行生产,即对x进行递加操作 */    {      x++;      printf("Producing : x=%d \n",x);      sleep(1);    }    if(x>=3) /* 当x的值等于3时,通知消费者 */    {      pthread_cond_signal(&cond); /* 激活等待的消费者线程 */      printf("Producing completed.\n",x);    }    pthread_mutex_unlock(&mutex); /* 对互斥量进行解锁操作 */    sleep(1);  }  pthread_exit(NULL); /* 终止当前线程 */}void consumer(void) /* 定义消费者线程运行的函数,其功能是对全局变量x进行逐减操作 */{  while(1)  {    pthread_mutex_lock(&mutex); /* 对互斥量进行加锁操作 */    while(x<3)    {      pthread_cond_wait(&cond,&mutex); /*阻塞消费者线程*/      printf("Start consuming.\n",x);    }    while(x>0) /* 当x的值大于0时,进行消费,即对x进行递减操作 */    {      x--;      printf("Consuming : x=%d \n",x);      sleep(1);    }    pthread_mutex_unlock(&mutex); /* 对互斥量进行解锁操作 */  }  pthread_exit(NULL); /* 终止当前线程 */} 53int main(void){  pthread_t id1,id2; /* 定义线程的标识符 */  int ret;  ret = pthread_mutex_init(&mutex, NULL); /* 对互斥量进行初始化 */  if(ret != 0)  {    printf ("Mutex initialization failed.\n");    exit (1);  }  ret = pthread_cond_init(&cond, NULL); /* 对条件变量进行初始化 */  if(ret != 0)  {    printf ("Conditions initialization failed.\n");    exit (1);  }  ret = pthread_create(&id1, NULL, (void *)&producer, NULL);/* 创建生产者线程 */  if(ret != 0)  {    printf ("Thread Producer creation failed.\n");    exit (1);  }  ret = pthread_create(&id2, NULL, (void *)&consumer, NULL);/* 创建消费者线程 */  if(ret != 0)  {    printf ("Thread Consumer creation failed.\n");    exit (1);  }  pthread_join(id1,NULL); /*线程合并 */  pthread_join(id2,NULL);  return (0);}

 

这个例程调用了“条件变量”,实现在某个条件下,对进程的阻塞和激活,编译运行后:

Product :x=1
Product :x=2
Product :x=3
Producing completed.
Start consuming.
Consuming:x=2
Consuming:x=1
Consuming:x=0
Product :x=1
Product :x=2
Product :x=3
Producing completed.
Start consuming.
Consuming:x=2
Consuming:x=1
Consuming:x=0

。。。。。。。

其关键循环条件的形成是在这句:

    for(i=0;i<3-x;i++) /* 当x的值小于3时,进行生产,即对x进行递加操作 */
    {
      x++;
      printf("Producing : x=%d \n",x);
      sleep(1);
    }

如果仔细对这个循环分析,你会发现这句话使x=2,即跳出。也就是说如果没有“条件变量”的话,将会输出:

x=1

x=2

x=1

x=2

即递增到2减到1 然后再递增到2。。。。。


那么有了条件变量后呢,程序是如何运行的呢?

线程1运行:

当x=2后,互斥量解锁,然后切换到线程2;

线程2运行:

判断x<3,然后阻塞此线程,切换到线程1;

线程1运行:

此时i重新赋值i=0,然后x++,当x=3时,线程1激活线程2,待线程1解锁后,切换到线程2;

线程2运行:

x- -,直到x=0,线程2解锁,切换到线程1;

。。。。。。


在实际运行中,也能明显感受到,X=2后,会停留比之前长的时间,然后才输出:X=3。这就是线程切换引起的延时。如果不仔细分析,我们会认为一个循环,线程只是切换了一次,其实不是这样的!


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值