NDK学习之路-C++线程篇

4 篇文章 0 订阅

前言

pthread 线程学习

一、线程的基本使用

1.如何引入外部库

在cmakeList中

  • 第一步:引入头文件
    # TODO 第一步:引入线程库的所有头文件
    include_directories("D:/NDK/CoursewareCreate/ndk_06/pthreads-w32-2-9-1-release/Pre-built.2/include")

  • 第二步:引入库文件(链接到库文件)
    # TODO 第二步:引入线程库的库文件 链接到库
    link_directories("D:/NDK/CoursewareCreate/ndk_06/pthreads-w32-2-9-1-release/Pre-built.2/lib/x86")
  • 第三步:链接到目标库
    # TODO 第三步:链接到目标库
    target_link_libraries(ClionTestProject pthreadVC2)
  • 第四步:使用时导入,头文件 pthread.h
    #include <pthread.h>
  • 第五步:线程库的一个坑
    # 第一个坑
    # TODO 第五步:解决那个宏没有定义的问题,不需要去修改源码
    # CXX 代表c++,   C代表c语言
    # "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS=AAA/BB/CC/DD.. 不破坏它的配置,在他的配置基础上 增加
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_STRUCT_TIMESPEC") # 定义 给 增加一个 预编译的宏 HAVE_STRUCT_TIMESPEC
    ​

2.线程的基本使用

线程的定义,

#include <iostream>
#include <string>

// TODO 第四步 导入 线程的 头文件
#include <pthread.h>

using namespace std;

// void *(PTW32_CDECL *start) (void *),
void * customPThreadMethod(void * pVoid) { // 能够接受所有的类型

    int result = *static_cast<int *>(pVoid);
    printf("我是耗时任务,我运行了,result:%d\n", result);

    for (int i = 0; i < 100; i++) {
        _sleep(200);
        printf("customPThreadMethod i:%d\n", (i + 1));
    }

    return 0; // 如果不返回,就会出现,很奇怪的问题
}

// 我们踩了第二个大坑
// 得到错误码:-1073741515 (0xC0000135)
// C:\Windows\SysWOW64  和  C:\Windows\System32  复制一份动态链接库进去

// TODO 线程的升级
void* customPThreadMethod02(void * pVoid) {
    for (int i = 0; i < 100; i++) {
        _sleep(200);
        printf("customPThreadMethod02 i:%d\n", (i + 1));
    }
    return 0; // 如果不返回,就会出现,很奇怪的问题
};

int main()
{
    cout << "ceshi"<<endl;
    // TODO 最简单的线程初始化
    /**
     * PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, 1.线程ID
                            const pthread_attr_t * attr,  2.线程属性
                            void *(PTW32_CDECL *start) (void *),  3.函数指针 ---> 异步任务 java run
                            void *arg); 4.函数指针的参数传递
     */
    /*pthread_t pthreadID; // 线程ID
    int value01 = 9988;
    pthread_create(&pthreadID, 0, customPThreadMethod, &value01);

    // 会等待耗时任务执行完成之后,才会打印执行下面的代码
    // pthread_join(pthreadID, 0);
    printf("线程执行完毕...\n");
    _sleep(3000);*/

    // TODO 线程的升级
    pthread_t pthreadID; // 线程ID, 允许有野指针
    pthread_attr_t pthreadAttr; // 线程属性,不允许有 野指针,有坑的

    float value = 6.5;

    // 初始化:线程属性
    pthread_attr_init(&pthreadAttr);

    // 什么是 分离线程  和 非分离线程 ?
    // 答:非分离线程,要等到耗时任务执行全部完成以后,先执行异步任务,才会执行join后面关联的代码逻辑
    //       分离线程,各玩各的,老死不相往来,所以就造成了,不管异步任务是否执行完毕,该结束就结束
    // pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED); // 开启分离线程,pthread_join效果丢失
    pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); // 开启非分离 和 pthread_join 关联起来了

    pthread_create(&pthreadID, &pthreadAttr, customPThreadMethod02, &value);
    // 先让耗时任务执行完毕后,在执行下面的代码
    pthread_join(pthreadID, 0); // join是第二个参数是线程执行完后返回的结果

    // 线程属性,进行回收
    pthread_attr_destroy(&pthreadAttr);

    return 0;
}

3.线程的高级使用

#include <iostream>
#include <string>

// TODO 第四步 导入 线程的 头文件
#include <pthread.h>

using namespace std;

// void *(PTW32_CDECL *start) (void *),
void * customPThreadMethod(void * pVoid) { // 能够接受所有的类型

    int result = *static_cast<int *>(pVoid);
    printf("我是耗时任务,我运行了,result:%d\n", result);

    for (int i = 0; i < 100; i++) {
        _sleep(200);
        printf("customPThreadMethod i:%d\n", (i + 1));
    }

    return 0; // 如果不返回,就会出现,很奇怪的问题
}

// 我们踩了第二个大坑
// 得到错误码:-1073741515 (0xC0000135)
// C:\Windows\SysWOW64  和  C:\Windows\System32  复制一份动态链接库进去

// TODO 线程的升级
void* customPThreadMethod02(void * pVoid) {
    for (int i = 0; i < 100; i++) {
        _sleep(200);
        printf("customPThreadMethod02 i:%d\n", (i + 1));
    }
    return 0; // 如果不返回,就会出现,很奇怪的问题
};

void * (*method)(void *pVoid){

};

int main()
{
    cout << "ceshi"<<endl;
    // TODO 最简单的线程初始化
    /**
     * PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, 1.线程ID
                            const pthread_attr_t * attr,  2.线程属性
                            void *(PTW32_CDECL *start) (void *),  3.函数指针 ---> 异步任务 java run
                            void *arg); 4.函数指针的参数传递
     */
    /*pthread_t pthreadID; // 线程ID
    int value01 = 9988;
    pthread_create(&pthreadID, 0, customPThreadMethod, &value01);

    // 会等待耗时任务执行完成之后,才会打印执行下面的代码
    // pthread_join(pthreadID, 0);
    printf("线程执行完毕...\n");
    _sleep(3000);*/

    // TODO 线程的升级
    pthread_t pthreadID; // 线程ID, 允许有野指针
    pthread_attr_t pthreadAttr; // 线程属性,不允许有 野指针,有坑的

    float value = 6.5;

    // 初始化:线程属性
    pthread_attr_init(&pthreadAttr);

    // 什么是 分离线程  和 非分离线程 ?
    // 答:非分离线程,要等到耗时任务执行全部完成以后,先执行异步任务,才会执行join后面关联的代码逻辑
    //       分离线程,各玩各的,老死不相往来,所以就造成了,不管异步任务是否执行完毕,该结束就结束
    // pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED); // 开启分离线程,pthread_join效果丢失
    pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); // 开启非分离 和 pthread_join 关联起来了

    pthread_create(&pthreadID, &pthreadAttr, customPThreadMethod02, &value);
    // 先让耗时任务执行完毕后,在执行下面的代码
    pthread_join(pthreadID, 0); // join是第二个参数是线程执行完后返回的结果

    // 线程属性,进行回收
    pthread_attr_destroy(&pthreadAttr);

    return 0;
}

 二、线程实现 生产者 消费者模式

工具类代码

// TODO 生产者 消费者 工具类

#ifndef NDK08_CODE_SAFE_QUEUE_TOOL_H
#define NDK08_CODE_SAFE_QUEUE_TOOL_H

#endif //NDK08_CODE_SAFE_QUEUE_TOOL_H

#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <string>
#include <queue>

using namespace std;

// 定义一个模板
template <typename T>

class SafeQueueClass
{
private:
    queue<T> queue; // 定义队列
    pthread_mutex_t mutex; // 定义互斥锁,为了线程安全处理 (不允许有野指针)
    pthread_cond_t cond; // 定义条件变量,为了实现  等待  读取 的功能 (不允许有野指针)

public:
    SafeQueueClass()
    {
        // 初始化 互斥锁
        pthread_mutex_init(&mutex, 0);

        // 初始化 条件变量
        pthread_cond_init(&cond, 0);
    }

    ~SafeQueueClass()
    {
        // 回收 互斥锁
        pthread_mutex_destroy(&mutex);

        // 回收 条件变量
        pthread_cond_destroy(&cond);
    }

    // TODO 加入队列中(进行生产)
    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);
    }

    // TODO 从队列中获取(进行消费)
    void get(T& t) { // 引用把值传出去
        // 为了保证同步的安全性,所以一进来,就锁上了
        pthread_mutex_lock(&mutex);

        // 用if可能有问题,可能会被系统唤醒
        while (queue.empty()) { // 没有数据可以消费
            // 条件变量 完成等待
            pthread_cond_wait(&cond, &mutex); // 这段代码,等待之后,有可能会被系统唤醒
        }

        // 证明被唤醒了
        t = queue.front(); // 得到 队列中的数据 仅此而已
        queue.pop(); // 把数据弹出去,删除掉

        // 解锁
        pthread_mutex_unlock(&mutex);
    }
};

 线程实现 生产者 消费者模式模拟使用

#pragma once

#include <iostream>

// TODO 为了学习  生产者 消费者 的工具类代码
#include "safe_queue_tool.h"

using namespace std;

SafeQueueClass<int> sq;

// TODO 模拟演示 消费者
void * getMethod(void * pVoid)
{
    while(9) {
        printf("getMethod\n");

        int value;
        sq.get(value);
        printf("消费者get 得到的数据:%d\n", value);

        // 你只要输入 -1 就结束当前循环
        if (-1 == value) {
            printf("消费者get 全部执行完毕...");
            break;
        }
    }

    return 0;
}

// TODO 模拟演示 生产者
void * setMethod(void * pVoid) {
    while (9) {
        printf("setMethod\n");

        int value;
        printf("请输入您要的信息....\n");
        cin >> value;
        // 你只要输入 -1 就结束当前循环
        if (-1 == value) {
            sq.add(value); // 这里添加是为了,让消费者,可以获得-1,进行停止
            printf("生产者set 全部执行完毕...");
            break;
        }
        sq.add(value);
    }

    return 0;
}

int main() {
    pthread_t  pthreadGet;
    pthread_create(&pthreadGet, 0, getMethod, 0);

    pthread_t pthreadSet;
    pthread_create(&pthreadSet, 0, setMethod, 0);

    pthread_join(pthreadGet, 0);

    cout << "AAAAAAAAAAAA..." << endl; // 线程任务执行结束后,才打印此语句

    pthread_join(pthreadSet, 0);

    cout << "main 函数执行..." << endl; // 线程任务执行结束后,才打印此语句

    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值