C++并发多线程--多个线程的数据共享和保护

目录

1--创建并等待多个线程

2--数据共享

2-1--数据只读

2-2--数据读写

2-3--共享数据保护简单案例


1--创建并等待多个线程

创建多个线程时,可以使用同一个线程入口函数;

多个线程的执行顺序与操作系统的调度机制有关,并不和创建线程的先后顺序相同;

一般会将多个线程对象存放在容器中,方便进行管理;

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>

// 线程入口函数
void myprint(int i){
    std::cout << "This is thread " << i << std::endl; 
}

int main(int argc, char *argv[]){
    std::vector<std::thread> V;
    // 创建5个线程
    for(int i = 0; i < 5; i++){
        V.push_back(std::thread(myprint, i));
    }

    // 等待5个线程
    for(auto iter = V.begin(); iter != V.end(); iter++){
        iter->join();
    }
    // 继续执行主线程
    std::cout << "This is main thread." << std::endl;
    return 0;
}

2--数据共享

2-1--数据只读

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>

// 共享只读数据
const std::vector<int> read_data = {1, 2, 3};

// 线程入口函数
void myprint(int i){
    // 只读数据
    std::cout << "thread " << i << " read data: " << read_data[0] << ","
    << read_data[1] << "," << read_data[2] << std::endl;
}

int main(int argc, char *argv[]){
    std::vector<std::thread> V;
    // 创建5个线程
    for(int i = 0; i < 5; i++){
        V.push_back(std::thread(myprint, i));
    }

    // 等待5个线程
    for(auto iter = V.begin(); iter != V.end(); iter++){
        iter->join();
    }
    // 继续执行主线程
    std::cout << "This is main thread." << std::endl;
    return 0;
}

2-2--数据读写

不同线程对共享数据进行读写时,可能会发生冲突,因此需要进行特殊的处理(例如加锁,线程间需互斥等);

2-3--共享数据保护简单案例

当两个线程对共享数据进行读写时,会发生冲突,可以通过互斥量(mutex) 来对共享数据进行加锁(lock) 、**解锁(unlock)**等操作;

lock() 与 unlock() 必须成对匹配,即调用次数相同;

必须使用同一个互斥量进行加锁和解锁;

需要选择正确的临界区进行上锁和解锁,即保护区域需正确;

cpp 复制代码
#include <iostream>
#include <thread>
#include <list>
#include <mutex> // 引入互斥

class myClass{
public:
    // 收集数据到消息队列
    void inMsgRecvQueue(){
        for(int i = 0; i < 100; i++){
            // 模拟收集消息
            std::cout << "Running inMsgRecvQueue(), insert one value: " 
                << i << std::endl; 

            // 选择正确的临界区进行加锁和解锁
            my_mutex.lock();
            msgRecvqueue.push_back(i); // 消息队列存储消息
            my_mutex.unlock();
        }
    }
    // 从消息队列取数据
    void outMsgRecvQueue(){
        for(int i = 0; i < 100; i++){
            if(!msgRecvqueue.empty()){
                // 选择正确的临界区并使用同一个互斥量进行加锁和解锁
                my_mutex.lock(); // 加锁
                // 取出数据
                int command = msgRecvqueue.front();
                msgRecvqueue.pop_front(); 

                my_mutex.unlock(); // 解锁
            }
            
            else{
                std::cout << "Running outMsgRecvQueue(), " 
                    "the msgRecvqueue is empty" << std::endl;
            }
        }
    }
private:
    std::list<int> msgRecvqueue; // 消息队列
    std::mutex my_mutex; // 创建互斥量 
};

int main(int argc, char *argv[]){
    myClass sample1;
    // 使用成员函数创建线程
    std::thread myInMsgObj(&myClass::inMsgRecvQueue, &sample1); // 收集数据线程
    std::thread myOutMsgObj(&myClass::outMsgRecvQueue, &sample1); // 取出数据线程
    myInMsgObj.join();
    myOutMsgObj.join();

    return 0;
}
相关推荐
papership1 小时前
【入门级-C++程序设计:12、文件及基本读写-文件的基本概念&文本文件的基本操作】
开发语言·c++·青少年编程
岁忧8 小时前
(nice!!!)(LeetCode 面试经典 150 题 ) 30. 串联所有单词的子串 (哈希表+字符串+滑动窗口)
java·c++·leetcode·面试·go·散列表
SunkingYang9 小时前
MFC/C++语言怎么比较CString类型最后一个字符
c++·mfc·cstring·子串·最后一个字符·比较
界面开发小八哥9 小时前
MFC扩展库BCGControlBar Pro v36.2新版亮点:可视化设计器升级
c++·mfc·bcg·界面控件·ui开发
R-G-B9 小时前
【15】MFC入门到精通——MFC弹窗提示 MFC关闭对话框 弹窗提示 MFC按键触发 弹窗提示
c++·mfc·mfc弹窗提示·mfc关闭弹窗提示·mfc按键触发 弹窗提示
十秒耿直拆包选手9 小时前
Qt:QCustomPlot类介绍
c++·qt·qcustomplot
珊瑚里的鱼9 小时前
第十三讲 | map和set的使用
开发语言·c++·笔记·visualstudio·visual studio
逑之9 小时前
C++笔记1:命名空间,缺省参数,引用等
开发语言·c++·笔记
berlin51519 小时前
c++判断文件或目录是否存在
c++
L_autinue_Star10 小时前
从0到1实现Shell!Linux进程程序替换详解
linux·运维·服务器·c++·chrome