zoukankan      html  css  js  c++  java
  • 线程竞争问题

    前言:   线程之间资源共享,所以不存在通信问题,但是会有很强烈的竞争问题,解决线程之间的竞争问题有以下几种方法:

    注:加锁不要太大,也尽量不要太多,否则会影响效率,读写锁结束最好放弃cpu调度

    1.互斥量

      功能:保证同一时间只有一个线程可以对共享资源进行操作,但是不保证同步

    步骤:

      1.1初始化互斥量:(2中方法,,一般常用静态,静态初始化用完后不需要删除)    

       动态初始化:

          static  pthread_mutex_t     mm;

          prhread_mutex_init(&mm,NULL);

       静态初始化:

          static  pthread_mutex_t    mm=PTHREAD_MUTEX_INITIALIZER;

      1.2 加/解锁操作

                 pthread_mutex_lock(&mm);//加锁操作,未获得锁的线程则阻塞等待

         pthread_mutex_trylock(&mm)//加锁操作,未获得锁的线程则非0返回,继续执行其他                   非竞争任务

         pthread_mutex_unlock(&mm)//解锁操作,解锁操作不会出错,即使没有锁也可以解锁

      1.3  销毁互斥量(锁)

            pthread_mutex_destroy(&mm)//   静态申请的不用销毁

    2.读写锁  :读共享    写独占

      功能:有时多个线程需要对同个资源进行读写操作时,可能会数据丢失等问题,如在写的时      候发生了读事件,而读写锁可以有效保证  读共享,写独占,主要用于既有读,又有      写,且读的数量远大于写

      优点:能够实现线程的高并发,但是线程的调度还不够精准(盲目调度)

      注意:每个线程执行完后应该放弃自己的时间片,这样可以解决线程饥饿问题

           sched_yield()       //放弃cpu调度  

      步骤:

      2.1   初始化读写锁(只能动态初始化)

          static   pthread_rwlock_t       rw;//声明一个全局锁变量

          pthread_rwlock_init(&rw,NULL)//初始化锁

      2.2   加/解锁

         pthread_rwlock_wrlock(&rw);   //加一把写锁,若加锁失败则阻塞在此

         pthread_rwlock_trywrlock(&rw);   //加写锁,若加锁失败则立即返回非0值执行其他工作

         pthread_rwlock_rdlock(&rw);    //加一把读锁,失败阻塞

         pthread_rwlock_tryrdlock(&rw);  //加读锁,失败非阻塞

         pthread_rwlock_unlock(&rw); //解锁(不分类型且不会失败)

      2.3    销毁锁

          pthread_rwlock_ destroy(&rw); 

    3.条件变量  

      功能:可以更好的协调多个线程工作,使cpu不会盲目调度,需要执行的线程收到信号后则执行,收不到信号的则睡眠等待信号。   通常需要合互斥量配合使用。互斥量保证同一时间只能有一个线程工作,条件变量能指定某个线程工作

      1初始化条件变量:(2种初始化方法,一般常用静态)

        1.静态初始化条件变量

          pthread_cond_t   ok=PTHREAD_COND_INITIALIZER;//申请一个变量名为ok的条件变量

               1.2 动态初始化条件变量:  

            pthread_cond_t   ok;

          pthread_cond_init(&ok,NULL);

      2.步骤:

      1.对竞争部分加互斥锁   pthread_mutex_lock(&mm);

      2.用while循环判断标志位,保证线程是收到信号后被唤醒的

         while(flag!=0)      {pthread_cond_wait(&no_ok,&mm); }

          ***********操作函数部分***********

      3.更改标志位  :flag

      4.解锁    pthread_mutex_unlock(&mm); 

      5.发送信号:pthread_cond_signal()  或  pthread_cond_broadcast()

      无论哪种等待方式,都必须和一个互斥锁配合,以防止多个线程同时请求                                                                          pthread_cond_wait((pthread_cond_timedwait(),下同)的竞争条件(Race   Condition),且在调用 pthread_cond_wait()前必须由本线程加锁(pthread_mutex_lock()),而在更新条件等待队列以前,mutex保持锁 定状态,并在线程挂起进入等待前解锁。在条件满足从而离开pthread_cond_wait()之前,mutex将被重新加锁,以与进入 pthread_cond_wait()前的加锁动作对应。   执行pthread_cond_wait()时自动解锁互斥量(如同执行了 pthread_unlock_mutex),并等待条件变量触发。这时线程挂起,不占用 CPU 时间,直到条件变量被触发。

    因此,全过程可以描述为:

    (1)pthread_mutex_lock()上锁,

    (2)pthread_cond_wait()等待,等待过程分解为为:解锁--条件满足--加锁

    (3)pthread_mutex_unlock()解锁。  
    激发条件有两种形式,pthread_cond_signal()激活一个等待该条件的线程,存在多个等待线程时按入队顺序激活其中一个;而pthread_cond_broadcast()则激活所有等待线程。 两者 如果没有等待的线程,则什么也不做。

     

       while(1)
        {
            pthread_mutex_lock(&mm);//首先加一把互斥锁,保证只有一个线程可以抢到锁,防止竞争
            while(flag!=0)  //加个循环防止_wait()被意外唤醒,
            {
               pthread_cond_wait(&no_ok,&mm);//等待唤醒信号,进入等待且原子性释放锁,收到信号并醒来,且需要持有锁,若加                  锁失败则等待
            }
            printf("input>");
            fgets(buf,4096,stdin);
            flag=1;
            pthread_mutex_unlock(&mm);  //释放锁
            pthread_cond_signal(&ok);    //发送信号
        }

  • 相关阅读:
    javascript Literal
    [MQ]消息队列产品的功能整理
    [MQ]消息队列与企业服务总线的简单比较,MQ&ESB
    [问题记录.Dotnet]混用不同版本odp组件造成的System.MissingMethodException错误
    [问题记录.Oracle/odp.net]数据库变化通知(Database Change Notification)的使用限制
    .net 中的 json 处理
    负载均衡器/负载均衡硬件简单比较
    [笔记.zipkin]用Docker搭建zipkin-rabbitmq-mysql环境(C#客户端-zipkin4net)
    [问题记录]配置zipkin数据存储到mysql时报错Access denied for user 'root'@'172.17.0.1' (using password: NO)
    [问题记录.Centos7]解决安装teamviewer失败——提示依赖 libQt5WebKitWidgets.so.5()(64bit) >= 5.5
  • 原文地址:https://www.cnblogs.com/edan/p/8946707.html
Copyright © 2011-2022 走看看