NDK 线程同步

使用场景

对底层代码进行 HOOK, 不可避免的要考虑多线程同步问题, 固然也能够写个相似 java 的线程本地变量来隔离内存空间。java

死锁分析

恩, 道理其实你们都懂的, 毕竟大学就学了操做系统,理论神马的窝就不讲了哈, 这里说说个人处理方法。首先线程同步问题主要是多线程对相同的可写内存进行操做致使的, 辣么咱们给这些可写的内存,每一个内存都加把锁不就得了, 哈哈,就这么简单, 咱们将存在多个线程访问的一块内存(好比说一个变量, 一个结构体,一个类)都配把锁, 这样确实就解决线程同步问题了, 可是做为一只程序员,必须打起12分的精神,时刻当心本身是否会掉坑里面去,这里也是哦, 若是按上面这么作,确实解决了多线程数据不一致问题,可是极有可能致使其余问题的出现, 好比死锁, 性能低下等, 固然咱也不须要慌, 上面的设计思路是正确的(可写的多线程共享内存加锁),咱们能够添加一些规范来规避这些问题;要想解决一个问题, 咱们必须可以知道这个问题发生的缘由是什么linux

死锁的简介:
线程A1, A2, 资源 R1, R2, 对应锁 RL1, RL2
A1的某个操做须要RL1, RL2
A2的某个操做须要RL2, RL1
说明: A1在获取RL2锁的时候阻塞了, A2在获取RL1锁的时候阻塞了c++

RL1            RL2
A 1--------------R1-------x------R2
                                    
                                    
RL2              RL1
A2  --------------R2-------x-------R1

嘛, 重上面的分析知道,产生死锁的条件有这些:(窝的见解, 理论的说法请自行百度)程序员

  1. 存在两个以上的锁(这是理所固然的啦, 若是只有一个锁,肿么可能存在死锁问题QAQ, 因此若是多线程共用一个锁,那就大胆的使用, 不用担忧死锁啦)
  2. 线程获取锁的顺序不一致, 理论一点的说法就是资源存在环形链(能够这么说,若是有多个锁, 可是全部的得到锁的顺序是同样的,那么这些锁其实等价于一个锁, 多块内存也能够看作一个大内存啦, 这个能够用反证法证实)

如何解决死锁

个人处理方法是这样的(各位大佬有更好的想法求评论区@)
减小锁嵌套, 也就是临界区的代码量尽可能小, 尽可能代码分开加锁,好比一个方法可能头部几行代码须要加锁, 和结束的几行须要加同一个锁, 咱们就不要将整个方法加锁了, 而是开头加锁,在结尾也加锁, 由于其余代码也有可能加锁了,若是方法整个加锁,辣么锁嵌套就没办法避免了
不要有循环锁的存在, 好比保持全部锁的获取顺序是相同的,辣么就不会有环路等待的条件啦(我在jni代码里面就是这么处理的)api

linux 互斥锁

嘛,互斥锁的主要做用是为了让代码进入临界区, 让一段代码能够成为原子操做, 理论上将这个功能只能由操做系统提供, 毕竟操做系统负责任务调度, 管理中断信息, 在 Java 和c++11 中都直接提供了api,c++11 中是 std::mutex, 然而个人 ndk 环境并无这个 api,因此就用了 linux 系统里面的 api 来实现了。数据结构

互斥锁

(互斥锁 = synchronized)
API说明多线程

//数据结构:
                    pthread_mutex_t
 //    行为:
 //       初始化:
 //          静态初始化:
                        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
                                        
 //          动态初始化:
                        int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *mutexattr);
       
 //          得到锁:
                        int pthread_mutex_lock(pthread_mutex *mutex);
                        int pthread_mutex_trylock(pthread_mutex_t *mutex);
 //          释放锁:
                        int pthread_mutex_unlock(pthread_mutex_t *mutex);
 //          销毁锁:
                        int pthread_mutex_destroy(pthread_mutex *mutex);
  
 // 以上能够发现命名规律, 文件名前缀_抽象的工能名_具体事务
 // 嘛,写c程序的话能够这么命名, 用c++的就没必要啦

使用说明

初始化----加锁--------释放锁------销毁锁函数

下面是我在ndk中封装的Lock性能

//SimpleLock.h;
   class SimpleLock
   {
       public :
       SimpleLock();
       void lock();
       void unlock();
       ~SimpleLockl();
 
       private:
       pthread_mutex_t __m;
     }
                      

  //SimpleLock.cpp
   SimpleLock::SimpleLock()
   {
      __m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
   }

   void SimpleLock::lock()
    {
       int ret = pthread_mutex_lock(&__m);
       assert(ret == 0);
   }

   void SimpleLock::unlock()
   {
       int ret = pthread_mutex_unlock(&__m);
       assert(ret == 0);
   }

   SimpleLock::~SimpleLock()
   {
       pthread_mutex_destory(&__m);
   }

特别注意

这里的加锁和解锁应该配对,应该配对,应该配对(重要的事情要说三变) ,最后不用了应该销毁, 应为这部份内存是没办法回收的, 因此说不用的时候要销毁掉,嘛,这里就写到析构函数里面啦, 若是是 c 写的...(额, 别忘了就好)操作系统

bug: 探针的获取ndk数据代码里面也是加了锁的,然而正常状况下没啥问题,若是数据有错, 该方法会直接返回, 可是返回的时候没有解锁!!!最后第二次获取数据的时候程序无响应了!!!

条件锁

(原本只想将总结互斥锁,可是条件锁很好玩,也就顺带看一下啦)

//嘛, 条件锁的做用我理解的就是linux给咱们实现的一个简单的观察者。
//      主要结构:
//      数据结构:
                                 pthread_cond_t cond_lock;
//      初始化:
//      静态:
                                 PTHREAD_COND_INITIALIZER
 
//      动态: 
                                 int pthread_cond_init(pthread_cond_t *cv,const pthread_condattr_t *cattr)
//      行为:
//      等待:
                                 int pthread_cond_wait(pthread_cond_t *cv,pthread_mutex_t *mutex);
//      通知:  
                                 int pthread_cond_signal(pthread_cond_t *cv);

使用场景

在临界区中某个由于知足某个条件而阻塞, 又应为某个条件知足而被唤醒,主要是若是不用条件锁, 若是某个线程须要特定条件才能执行, 而这个条件依赖去其余线程, 那么就要让这个线程隔一段时间查询一下状态,知足则执 行,不然阻塞,这样会致使性能问题, 因此条件锁能够在状态知足条件的时候通知阻塞的线程执行。并且通常来讲条件锁和互斥锁要一块儿用。

pthread_mutex_t m;
     pthread_cond_t c;


  线程一:
       pthread_mutex_lock(&m);
        if (条件不知足)
            {
                  pthread_cond_wait(&c, &m);//等待状态知足后再执行
            }
         pthread_mutex_unlock(&m);
                     
  线程二:
        pthread_mutex_lock(&m);
               ...
        if (条件知足) //线程一能够执行了
           {
                  pthread_cond_signal(&c);
           }
               ...
        pthread_mutex_unlock(&m);
相关文章
相关标签/搜索