美文网首页NDK开发
NDK---C++篇(六)C++线程pthread

NDK---C++篇(六)C++线程pthread

作者: 初夏的雪 | 来源:发表于2021-06-20 19:42 被阅读0次

    C++ 11 之后出现了线程pthread ,今天我们来认识一下:

    1、创建线程 pthread_create

    说明:

          **参数说明:**
    
                  **第一个参数:线程ID**
    
                  **第二个参数:线程属性,用0即可**
    
                  **第三个参数:函数指针(耗时操作函数名)**
    
                  **第四个参数:函数指针的参数**
    

    引入库:#include <pthread.h>

    1、c++中的线程和main函数默认是互不相关的,也就是说main函数弹栈后不管子线程是否完成,就会结束子线程(允许异常)

    2、可以使用join来让子线程完成后再执行join后面的代码,直至main函数弹栈

    3、千万不要让main函数睡眠的方式等待异步线程

    示例代码:

    // 异步线程  相当于Java的Thread.run函数一样
    void *customPthreadTask(void *pVoid) {
        // C++转换static_cast  转换指针操作的
        int *number = static_cast<int *>(pVoid); // pVoid==number int的地址,所以我用int*接收,很合理
        cout << "异步线程执行了:" << *number << endl;
    
        for (int i = 0; i < 10; ++i) {
            cout << "run:" << i << endl;
            sleep(1);
        }
        return 0; // 必须返回
    }
    
    int main(){
        int number = 9527;
        pthread_t pthreadID; // 线程ID,每个线程都需要有的线程ID
        pthread_create(&pthreadID, 0, customPthreadTask, &number);
        pthread_join(pthreadID,0);  //此处不join,会随着main函数弹栈,而结束子线程
        return 0;
    }
    
    
    
    /**
    异步线程执行了:9527
    run:0
    run:1
    run:2
    run:3
    run:4
    run:5
    run:6
    run:7
    run:8
    run:9
    */
    

    2、分离线程和非分离线程

    说明:

      **1、分离线程:各个线程都是自己运行自己的,互不相关。例如:main函数结束,就全部结束,不会等待异步线程。**
    
                              **多线程情况下使用**
    
      **2、非分离线程:线程之间有协作的能力,例如:main函数会等待异步线程执行完后,再执行后面的代码**
    
                              **协作、顺序指向的场景**
    

    3、互斥锁(相当于java的synchronize)

    说明:

      **1、不允许有野指针,所有必须要初始化**
    
      **2、pthread_mutex_init 初始化  、pthread_mutex_destroy销毁锁,必须成对出现,两者之间的代码是加了锁的;**
    

    示例代码:

    
    queue<int> data;//全局的存储队列
    pthread_mutex_t mutex;//定义一个互斥锁,不允许有野指针
    
    
    void *task(void *pVoid) {
        pthread_mutex_lock(&mutex); // 锁住
        cout << "当前线程的标记是:" << *static_cast<int *>(pVoid) << endl;
        if (!data.empty()) {
            printf("获取队列的数据:%d\n", data.front());
            data.pop(); // 删除
        } else {
            printf("没有数据了\n");
        }
        sleep(1);
        pthread_mutex_unlock(&mutex); // 解锁
        return 0;
    }
    
    int main(){
        
         //初始化
        pthread_mutex_init(&mutex, NULL);
    
        // 给队列 初始化数据 手动增加数据进去
        for (int i = 10001; i < 10111; ++i) {
            data.push(i);
        }
    
        //定义10个线程
        pthread_t pthreadIDArray[20];
        for (int i = 0; i < 20; ++i) {
            pthread_create(&pthreadIDArray[i], 0, task, &i);
    
            // 不能使用 join,如果使用(就变成顺序的方式,就没有多线程的意义了,所以不能写join)
            // pthread_join(pthreadIDArray[i], 0);
        }
    
        sleep(20);
    
        // 销毁 互斥锁
        pthread_mutex_destroy(&mutex);
        
        return 0;
    }
    

    4、条件变量+互斥锁 == Java版本的(notify 与 wait 操作)

    说明:

      **pthread_cond_broadcast====Java notifyAll 所有的**
    
       **pthread_cond_signal=====  Java notify 单个的**
    

    1、互斥锁(pthread_mutex_t)、条件变量(pthread_cond_t)都不允许有野指针

    2、结合使用时, 初始化:先初始化互斥锁,再初始化条件变量;

                              **释放:先回收互斥锁,再回收条件变量;**
    

    1)定义一个模板队列:

    #include <iostream>
    #include <string>
    #include <pthread.h>
    #include <string>
    #include <queue>
    using namespace std;
    
    template<typename  T>
    
    class SafeQueue{
    private:
        queue<T> queue;
        pthread_mutex_t  mutex; // 定义互斥锁(不允许有野指针)
        pthread_cond_t cond; // 条件变量,为了实现 等待 读取 等功能 (不允许有野指针)
    public:
        SafeQueue(){
            // 初始化 互斥锁
            pthread_mutex_init(&mutex, 0);
    
            // 初始化 条件变量
            pthread_cond_init(&cond, 0);
        }
        ~SafeQueue() {
            // 回收 互斥锁
            pthread_mutex_destroy(&mutex);
    
            // 回收 条件变量
            pthread_cond_destroy(&cond);
        }
    public:
        void add(T t){
            // 为了安全 加锁
            pthread_mutex_lock(&mutex);
    
            queue.push(t); // 把数据加入到队列中
            // 告诉消费者,我已经生产好了
            // pthread_cond_signal(&cond) // Java notify 单个的
            pthread_cond_broadcast(&cond); // Java notifyAll 所有的的
    
            // 解锁
            pthread_mutex_unlock(&mutex);
        }
        void get(T & t){
            // 为了安全 加锁
            pthread_mutex_lock(&mutex);
    
            while (queue.empty()) {
                cout << "等待中.." << endl;
                pthread_cond_wait(&cond, &mutex); // 相当于 Java的 wait 等待了[有可能被系统唤醒]
            }
    
            // 证明被唤醒了
            t = queue.front(); // 得到 队列中的元素数据 仅此而已
            queue.pop(); // 删除元素
    
            // 解锁
            pthread_mutex_unlock(&mutex);
        }
    };
    

    2)模拟生产者、消费者

    #include "SafeQueue.h"
    SafeQueue<int> sq;
    
    // TODO 模拟演示 消费者
    void *getMethod(void *) {
        while (true) {
            int value;
            sq.get(value);
            printf("消费者get 得到的数据:%d\n", value);
    
            // 你只要传入 -1 就结束当前循环
            if (-1 == value) {
                break;
            }
        }
        return 0;
    }
    
    // TODO 模拟演示 生产者
    void *setMethod(void *) {
        while (true) {
            int value;
            printf("请输入你要生成的信息:\n");
            cin >> value;
            sq.add(value);
            if (value == -1) {
                break;
            }
        }
        return 0;
    }
    
    
    int main(){
        pthread_t pthreadGet;
        pthread_create(&pthreadGet, 0, getMethod, 0);//1
        
        pthread_t pthreadSet;
        pthread_create(&pthreadSet, 0, setMethod, 0);//2
    
        pthread_join(pthreadGet, 0);//不能在线程创建成功就join ,否则达不到两个线程同时执行的效果
        pthread_join(pthreadSet, 0);
        return 0;
    }
    

    这一节的内容其实和java的对比着学习,会比较容易理解些。

    特别需要注意的是:

    <u>加锁与销毁锁是成对出现的,千万不要忘记销毁锁;</u>
    

    下节预告:智能指针

    相关文章

      网友评论

        本文标题:NDK---C++篇(六)C++线程pthread

        本文链接:https://www.haomeiwen.com/subject/pafyjltx.html