美文网首页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