APUE学习(六):线程同步


(一)互斥量作用


1、保护不安全的库函数。

说一个函数是线程安全的,意思是同一时刻可以被多个线程安全调用,而不会发生脏数据之类的事情

pthread_mutex_lock(&mutex)
unsafe_function()//调用不安全的库函数
pthread_mutex_unlock(&mutex)

2、对标志符和全局变量进行同步

同上,只是把库函数修正为标志符和变量

只能短时间持有,等待输入这样的持续时间不确定的情况,用条件变量来同步。

(二)条件变量

为什么会有条件变量,忙等可能使得其他的线程不能得到cpu。

假设两个变量x和y被多个线程共享。我们希望线程一直等到x和y相等为止。
典型的不正确的忙等解决方法是:while(x != y);
根据线程的调度方式,执行忙等的线程可能永远都不会让其他的线程使用cpu,这样x和yde 值永远也不会变了。同时对共享变量的访问也应该被保护起来。
等待断言x==y 为真的正确的非忙等策略:
a.锁定互斥量
b.测试条件x==y
c.如果为真,解除对互斥量的锁定,并推出循环
d.如果为假,将 线程挂起,并解除对互斥量的锁定
问题在于:如何保证解除互斥量的锁定和线程挂起之间x和y没有发生改变。
解决办法:解除锁定和挂起必须是原子操作(pthread_cond_wait)


(三)信号量 (这个apue上没有介绍,之前windows我有用到就顺便整理了一下,线程和进程都能用

对信号量的理解,可以参照mutex,mutex的值为1或者0(lock为1,unlock为0)。而信号量是wait到的时候sem-1,等sem减小到0就挂起,post的时候sem+1,并唤起挂起的线程。附上一则例子

/*
 *生产者消费者关于信号的例子
 *通过两个信号量,一个blank 一个product。生产前先将blank -1(sem_wait) ,减少到0就挂起
 *product就+1(sem_post),唤起挂起等待的线程
 *
 *这里应该也可以使用一个信号量来完成这个例子
 */

#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>

#define NUM 5

int queue[NUM];
sem_t blank_number,product_number;

void* producer(void* arg)
{
  int p=0;
  while(1)
  {
    sem_wait(&blank_number);

    queue[p]=rand()%1000 +1;
    printf("produce id=%d,value=%d\n",p,queue[p]);

    sem_post(&product_number);
    p=(p+1)%NUM;
    sleep(rand()%3);

  }
}

      
void* consumer(void* arg)
{
  int c=0;
  while(1)
  {
    sem_wait(&product_number);


    printf("=========================consumer id=%d,value=%d\n",c,queue[c]);
    queue[c] = 0;

    sem_post(&blank_number);
    c=(c+1)%NUM;
    sleep(rand()%3);
  }
}


int main(int argc,char* argv[])
{
  pthread_t tid_p,tid_c;
  int ret_p,ret_c;

  sem_init(&blank_number,0,NUM);
  sem_init(&product_number,0,0);

  ret_p = pthread_create(&tid_p,NULL,producer,NULL);
  if(ret_p != 0)
    printf("pthread create error\n");

  ret_c = pthread_create(&tid_c,NULL,consumer,NULL);
  if(ret_c != 0)
    printf("pthread consumer create error\n");


  pthread_join(tid_p,NULL);
  pthread_join(tid_c,NULL);

  sem_destroy(&blank_number);
  sem_destroy(&product_number);

  exit(0);
}


(四)读写锁

也叫共享-独占锁。

当读写锁是写加锁状态时,在解锁之前试图对这个锁加锁的线程都会被阻塞。

当读写锁是读加锁状态时,所有以读模式对他进行加锁的线程都可以得到访问权;所有希望以写模式对此锁进行加锁的线程,必须阻塞直到所有的线程释放读锁(这种情况下读写锁通常会阻塞随后的读模式锁请求,避免读模式锁长期占用,而等待的写模式所请求得不到满足)。


    
POSIX 函数
互斥锁
pthread_mutex_t
pthread_mutex_destroy
pthread_mutex_init
pthread_mutex_lock
pthread_mutex_trylock
pthread_mutex_unlock
条件变量
pthread_cond_destroy
pthread_cond_init
pthread_cond_broadcast
pthread_cond_signal
pthread_cond_timewait
pthread_cond_wait
读--写锁
pthread_rwlock_destroy
pthread_rwlock_init
pthread_rwlock_rdlock
pthread_rwlock_wrlock
pthread_rwlock_timedrdlock
pthread_rwlock_timewrlock
pthread_rwlock_tryrdlock
pthread_rwlock_trywrlock

(五)效率问题

明显的使用同步这些机制会给程序的运行带来负担,总体感觉结合条件变量就比单纯的使用mutex效率高些,真正的效率如何我没能找到资料证实。留待以后查证或者验证。


之前对线程同步这一块比较敬畏,老感觉吃不透。事实上这一块也算是比较难用的。实际的工作中对同步还是接触到的比较少,之前写的类似网关的程序虽然也是多线程并发,但是需要同步的处理也是比较少。现在接触的软件模型中数据库这种多种用户实时读写的应用比较需要。而用户之间交互比较少的应用模型就很少用到这些了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值