互斥变量和条件变量

线程的同步
        POSIX提供了两个同步的原语,mutex(互斥)和condition(条件)变量。互斥是可以被用来控制共享变量的访问简单的锁原语。注意,对于线程来说,整个地址空间都是共享的,所以所有的东西都可以被当作共享资源。然而,在大多数情况下,线程使用私有的本地变量(在pthread_create 及连续的函数中制造出来的)单独的工作(理论上),并通过全局变量来把它们的成果合并起来。对于线程都要进行写操作的变量的访问必须被控制。
让我们创建一个readers/writers程序,在这个程序中有一个reader和一个writer通过一个共享的缓存来通信并且通过互斥来控制访问:
  void reader_function(void);
  void writer_function(void);
 
  char buffer;
  int buffer_has_item = 0;
  pthread_mutex_t mutex;
  struct timespec delay;
 
  main()
  {
     pthread_t reader;
 
     delay.tv_sec = 2;
     delay.tv_nsec = 0;
 
     pthread_mutex_init(&mutex, pthread_mutexattr_default);
     pthread_create( &reader, pthread_attr_default, (void*)&reader_function,
                    NULL);
     writer_function();
  }
 
  void writer_function(void)
  {
     while(1)
     {
          pthread_mutex_lock( &mutex );
          if ( buffer_has_item == 0 )
          {
               buffer = make_new_item();
               buffer_has_item = 1;
          }
          pthread_mutex_unlock( &mutex );
          pthread_delay_np( &delay );
     }
  }
 
  void reader_function(void)
  {
     while(1)
     {
          pthread_mutex_lock( &mutex );
          if ( buffer_has_item == 1)
          {
               consume_item( buffer );
               buffer_has_item = 0;
          }
          pthread_mutex_unlock( &mutex );
          pthread_delay_np( &delay );
     }
  }
       在这个简单的程序中我们假设缓存只能容纳一项,所以它一直是处于两种状态的其中一种,有内容或没有。writer首先锁住互斥变量,如果已经被上锁了,那么该线程阻塞直到被解锁,然后查看缓存是否为空。如果缓存为空,它创建一个新的项并设置标记buffer_has_item,因此reader会知道现在缓存里有内容。然后解锁互斥变量并延时2秒钟让reader有机会消耗这项内容。这个延时与我们的前一个延时不同,它是用来改善程序性能的。如果没有这个延时,writer在释放锁之后可能马上又获得了锁并试图再制造另一项内容。reader很可能没有机会这么快的消耗这项内容,所以延时是一个好办法。
        reader的情况也差不多。他获得这个锁,查看是否存在内容,如果有就消耗它。它释放锁并延时一小段时间来给writer机会去制造新的内容。在这个例子中reader和writer会一直执行下去,制造和消耗内容。如果一个互斥变量不再被需要,可以通过pthread_mutex_destroy (&mutex)来释放。观察在互斥变量的初始化函数中,我们使用被要求的pthread_ mutexattr_default作为互斥变量的属性。在OSF/1中,互斥变量属性没什么作用,所以强烈推荐使用默认值。
        适当的使用户斥变量保证消除了竞争情形。但是,互斥变量本身十分的弱,因为它只有两个状态:被锁和未被锁。POSIX的条件变量通过允许一个线程阻塞而去等待另一个线程的信号来补充互斥变量。当这个信号被接受到了,被阻塞的信号被唤醒去尝试获得一个与之像关的互斥变量。因此信号和互斥可以被合并起来消除 readers/writers带来的自旋锁问题。我们已经设计了一个通过pthreads的mutex和condition实现的简单的整数信号量并且今后会在那个环境中讨论同步的问题。信号量的代码可以在附录A中找到,关于条件变量的细节问题
可以在帮助(man)页中找到。

本节提到的函数:
pthread_mutex_init(), pthread_mutex_lock(),
pthread_mutex_unlock(), and pthread_mutex_destroy().

 
### 互斥锁 #### 使用 在树莓派上进行 C 语言开发时,互斥锁可用于保护共享资源,防止多个线程同时访问造成数据不一致。使用步骤通常包括初始化互斥锁、加锁、访问共享资源、解锁销毁互斥锁。 #### 原理 互斥锁是一种同步原语,它提供了一种简单的方式来确保在同一时间只有一个线程可以访问共享资源。当一个线程获得互斥锁时,其他试图获取该互斥锁的线程将被阻塞,直到持有锁的线程释放它。 #### 示例 ```c #include <stdio.h> #include <pthread.h> // 定义互斥锁 pthread_mutex_t mutex; // 共享资源 int shared_variable = 0; // 线程函数 void *thread_function(void *arg) { // 加锁 pthread_mutex_lock(&mutex); // 访问共享资源 shared_variable++; printf("Thread incremented shared_variable to %d\n", shared_variable); // 解锁 pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t thread; // 初始化互斥锁 pthread_mutex_init(&mutex, NULL); // 创建线程 pthread_create(&thread, NULL, thread_function, NULL); // 等待线程结束 pthread_join(thread, NULL); // 销毁互斥锁 pthread_mutex_destroy(&mutex); return 0; } ``` ### 条件变量 #### 使用 条件变量用于线程间的同步,当一个线程需要等待某个条件满足时,可以使用条件变量进行等待。当条件满足时,其他线程可以通过条件变量通知等待的线程。使用步骤包括初始化条件变量、等待条件、发出通知销毁条件变量。 #### 原理 条件变量允许线程在某个条件不满足时阻塞,直到其他线程发出信号表示条件已经满足。条件变量通常与互斥锁一起使用,以确保在检查条件等待条件的过程中共享资源的一致性。 #### 示例 ```c #include <stdio.h> #include <pthread.h> // 定义互斥条件变量 pthread_mutex_t mutex; pthread_cond_t cond; // 共享资源标志 int shared_variable = 0; int condition_met = 0; // 生产者线程函数 void *producer(void *arg) { // 加锁 pthread_mutex_lock(&mutex); // 修改共享资源 shared_variable = 1; condition_met = 1; // 发出通知 pthread_cond_signal(&cond); // 解锁 pthread_mutex_unlock(&mutex); return NULL; } // 消费者线程函数 void *consumer(void *arg) { // 加锁 pthread_mutex_lock(&mutex); // 等待条件满足 while (!condition_met) { pthread_cond_wait(&cond, &mutex); } // 访问共享资源 printf("Consumer found shared_variable = %d\n", shared_variable); // 解锁 pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t producer_thread, consumer_thread; // 初始化互斥条件变量 pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); // 创建生产者消费者线程 pthread_create(&producer_thread, NULL, producer, NULL); pthread_create(&consumer_thread, NULL, consumer, NULL); // 等待线程结束 pthread_join(producer_thread, NULL); pthread_join(consumer_thread, NULL); // 销毁互斥条件变量 pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值