NDK03

作者: 星云春风 | 来源:发表于2020-05-21 23:49 被阅读0次

结构体

结构体里所有的成员,都是public的

// TODO xia chen hui 2020/5/21 21:58 结构体
struct Student {
    // xia chen hui 2020/5/21 21:59 里面所有的成员,都是public
    char *name;
    int age;
    char sex;
};

共用体

在内存中只存在一个值

// TODO xia chen hui 2020/5/21 22:18 共用体
union MyCount {
    int countValue1;
    int countValue2;
    int countValue3;
    int countValue4;
    int countValue5;
    int countValue6;
    int countValue7;
};
    // TODO xia chen hui 2020/5/21 22:20 共用体
    union MyCount myCount;
    myCount.countValue1 = 10;
    printf("myCount的值%d\n", myCount.countValue1); //输出10
    myCount.countValue2 = 20;
    printf("myCount的值%d\n", myCount.countValue1);//输出20,countValue1的值被改了

分离线程和非分离线程

分离线程:线程之间自己管自己,不管其他的,所以不管线程是否执行完毕,该结束就结束。
非分离线程:先执行异步任务,要等到耗时任务完成之后,才会执行join后面的关联代码

  • 线程是有步骤
CmakeLists中
# 第一步,引入线程库的所有头文件
include_directories("C:/Users/Administrator/Desktop/pthreads-w32-2-9-1-release/Pre-built.2/include")
# 第二步,引入线程库的库文件,链接到库
link_directories("C:/Users/Administrator/Desktop/pthreads-w32-2-9-1-release/Pre-built.2/lib/x64")
# 第三步,链接到目标库
target_link_libraries(ndk03_code_cpp pthreadVC2)
#第五步,解决宏没有定义的问题,但是第二步选择64位的时候,好像不需要这一步
# cxx代表C++,
# "${CMAKE_CXX_FLAGS}"  CMAKE_CXX_FLAGS =AAA/BB/CC....  表示不破坏他的配置,在他的配置基础上增加
# -DHAVE_STRUCT_TIMESPEC代表增加HAVE_STRUCT_TIMESPEC这个宏,和D之间不能有空格
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_STRUCT_TIMESPEC")


#第四步在cpp文件中是导入头文件
#第六步,需要把C:\Users\Administrator\Desktop\pthreads-w32-2-9-1-release\Pre-built.2\dll 里的动态链接库pthreadVC2.dll交叉复制到C:\Windows的system32 和SysWOW64中。32复制到64  ,64复制到32
  • 线程普通用法
//定义函数指针规则
void *customPthreadMethod(void *pVoid) {
    //void *代表能接受所有类型
    // static_cast<int *>(pVoid)代表把空指针转换为int类型的指针,然后加上*取出内存地址对应的值
    int result = *static_cast<int *>(pVoid);
    printf("耗时任务被执行...%d\n", result);
    for (int i = 0; i < 50; ++i) {
        Sleep(200);
        printf("customPthreadMethod: i=%d\n", (i + 1));
    }
    //如果不返回,就会出现问题
    return 0;
}

//最简单有用法
void simpleThreadTest() {
    cout << "124" << endl;
    pthread_t pthreadID;//线程ID
// xia chen hui 2020/5/28 0:11 参数1.线程id  2.线程属性 3.函数指针,执行异步任务,类似java的run 4.函数指针的参数传递
    int value01 = 4512;
    //会把value01传给customPthreadMethod
    pthread_create(&pthreadID, 0, customPthreadMethod, &value01);
    //pthread_join会等待耗时任务执行完成之后,才会执行后面的代码
    pthread_join(pthreadID, 0);
    printf("线程执行完毕...");

}
  • 线程升级用

//线程升级用法
void *customPthreadMethod2(void *pVoid) {

    float result = *static_cast<float *>(pVoid);
    printf("2耗时任务被执行...%f\n", result);
    for (int i = 0; i < 50; ++i) {
        Sleep(100);
        printf("customPthreadMethod2: i=%d\n", (i + 1));
    }
    return 0;
}

void customThreadTest() {
    pthread_t pthreadID;//允许有野指针
    pthread_attr_t pthreadAttr; //线程属性,不允许有野指针
    //需要初始化线程属性,需要指针类型,所以传内存地址
    pthread_attr_init(&pthreadAttr);

    // TODO xia chen hui 2020/5/28 23:38 分离线程 和 非分离线程
    // xia chen hui 2020/5/28 23:38  非分离线程:先执行异步任务,要等到耗时任务完成之后,才会执行join后面的关联代码
    // xia chen hui 2020/5/28 23:38 分离线程:线程之间自己管自己,不管其他的,所以不管线程是否执行完毕,该结束就结束。

    //开启分离线程。pthread_join会失效
    //pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);


    //开启非分离线程和pthread_join相关联
    pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE);

    float value = 12.3;
    pthread_create(&pthreadID, &pthreadAttr, customPthreadMethod2, &value);
    //耗时任务完成之后再执行 ,join第二个参数是线程执行完成后的返回结果
    pthread_join(pthreadID, 0);
    printf("customThreadTest线程完成之后...\n");

    //完成之后回收
    pthread_attr_destroy(&pthreadAttr);


}
  • 线程互斥锁
// TODO xia chen hui 2020/5/28 23:51 线程的升级,  线程安全问题 互斥锁
#include <iostream>
#include <pthread.h>
#include <string>
#include <queue>

using namespace std;

//定义全局的队列
queue<int> saveAllData;

//定义一个互斥锁,不允许野指针
pthread_mutex_t mutex;

void *customThreadMethod(void *pVoid) {
    // 10个线程,同时对队列的数据进行操作,并保证数据安全,(加锁)
    //加锁
    pthread_mutex_lock(&mutex);
    printf("当前线程标记是-----------%d\n", *static_cast<int *>(pVoid));
    if (!saveAllData.empty()) {
        printf("获取队列的数据:%d\n", saveAllData.front());
        //把数据弹出去(删除)
        saveAllData.pop();
    } else {
        printf("队列中没有数据了...");
    }
    //解锁,为了让其他线程可以进来操作
    pthread_mutex_unlock(&mutex);
    return 0;
}

int main() {

    //初始化互斥锁
    pthread_mutex_init(&mutex, NULL);
    //给队列初始化数据
    for (int j = 1000; j < 1030; ++j) {
        saveAllData.push(j);
    }
    //初始化线程id
    pthread_t pthreadIDArray[30];
    for (int i = 0; i < 30; ++i) {
        //for循环开启线程
        pthread_create(&pthreadIDArray[i], 0, customThreadMethod, &i);
    }
    //回收互斥锁
    pthread_mutex_destroy(&mutex);
    printf("main函数已经结束...");

    //阻塞main ,为了让多线程执行完成
    system("pause");


    return 0;
}

  • 生产者 消费者
// TODO xia chen hui 2020/5/29 20:29 生产者 消费者 工具类

#ifndef NDK03_CODE_CPP_SAFE_QUEUE_TOOL_H
#define NDK03_CODE_CPP_SAFE_QUEUE_TOOL_H

#endif //NDK03_CODE_CPP_SAFE_QUEUE_TOOL_H

#include <iostream>
#include <string>
#include <pthread.h>
#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, NULL);
        //初始化条件变量
        pthread_cond_init(&cond, NULL);
    }

    ~SafeQueueClass() {
        //回收互斥锁
        pthread_mutex_destroy(&mutex);
        //回收条件变量
        pthread_cond_destroy(&cond);
    }

    // TODO xia chen hui 2020/5/29 20:49 加入队列中(进行生产)
    void add(T t) {
        //为了保证同步的安全性,所以锁定
        pthread_mutex_lock(&mutex);

        queue.push(t);
        //这里需要唤醒消费者,否则消费者会一直等待,
        //pthread_cond_signal(&cond); //系统去唤醒一个线程,--java notify
        //唤醒所有的线程,---java notifyAll
        pthread_cond_broadcast(&cond);
        //解锁
        pthread_mutex_unlock(&mutex);

    }

    // TODO xia chen hui 2020/5/29 20:51 从队列中获取(进行消费)
    void get(T &t) {
        //为了保证同步的安全性,所以锁定
        pthread_mutex_lock(&mutex);
        //if 可能有问题,
        while (queue.empty()) {
            //没有数据可以消费了,所以开始等待
            pthread_cond_wait(&cond, &mutex);//用if 等待之后,可能会被系统唤醒
        }


        //证明已经被唤醒了,开始消费
        //取出首元素,得到队里中的数据
        t = queue.front();
        //把数据弹出去(删除)
        queue.pop();

        //解锁
        pthread_mutex_unlock(&mutex);
    }
};
#include "safe_queue_tool.h"


using namespace std;

SafeQueueClass<int> safeQueueClass;

// TODO xia chen hui 2020/5/29 21:04 模拟消费者
void *getMethod(void *pVoid) {
    //非0 就是true
    while (1) {
        int value;
        safeQueueClass.get(value); //这里value 就有值了
        printf("getMethod的value =%d\n", value);
        //为了结束循环,如果输入-1, 就结束
        if (-1 == value) {
            printf("消费者执行完毕...\n");
            break;
        }
    }
    return 0;
}

// TODO xia chen hui 2020/5/29 21:05 模拟生产者
void *setMethod(void *pVoid) {
    while (1) {
        printf("setMethod\n");
        printf("请输入信息....\n");
        int value;
        cin >> value;
        //为了结束循环,如果输入-1, 就结束
        if (-1 == value) {
            //为了让消费者可以获取-1  进行停止
            safeQueueClass.add(value);
            printf("生产者执行完毕...\n");
            break;
        }
        //添加进去
        safeQueueClass.add(value);

    }
    return 0;
}

int main() {
    pthread_t pthreadGet;
    pthread_t pthreadSet;

    pthread_create(&pthreadGet, 0, getMethod, 0);
    pthread_create(&pthreadSet, 0, setMethod, 0);

    pthread_join(pthreadGet, 0);
    pthread_join(pthreadSet, 0);
    printf("main函数执行...\n");

    return 0;
}

相关文章

  • NDK03

    结构体 结构体里所有的成员,都是public的 共用体 在内存中只存在一个值 分离线程和非分离线程 分离线程:线程...

网友评论

      本文标题:NDK03

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