0


【C++】验证STL容器线程不安全

文章目录

概要

在并发编程中,线程安全是确保多个线程在同时访问共享资源时,不会引起数据竞争或意外的行为。在C++中,std::vector通常并不是线程安全的,因此在多线程环境中对std::vector进行读写操作可能会导致未定义行为。本文将通过实例验证std::vector的线程不安全性,并讨论如何解决这一问题。

整体架构流程

本文将分以下几部分讲解如何验证std::vector的线程不安全性:
1、多线程操作std::vector示例代码:构建一个简单的C++代码示例,在多线程中对std::vector执行插入和读取操作。
2、问题分析:分析代码在运行时出现的线程问题,分析出现的原因
3、解决方法:介绍一下解决的方法。

技术名词解释

线程安全(Thread Safety):指在多线程程序中,多个线程访问共享资源时,不会产生数据竞争或未定义行为。
数据竞争(Data Race):多个线程并发访问共享资源,并且至少一个线程执行写操作时,发生的竞争现象。
锁(Mutex):一种同步机制,用于防止多个线程同时访问共享资源。

技术细节

示例代码

以下代码展示了一个多线程环境中对std::vector进行读写操作的示例,验证其线程不安全性。

#include<iostream>#include<pthread.h>#include<string>#include<vector>#include<unistd.h>usingnamespace std;classThread{public:Thread(string &name):_threadname(name){}boolstart(){sleep(1);//这里sleep是为了让现象变得固定,不加sleep,则现象就太随机,不容易画图分析int n =pthread_create(&_tid,nullptr, threadroutine,this);if(n ==0){returntrue;}returnfalse;}staticvoid*threadroutine(void*args){
       
        Thread *self =static_cast<Thread *>(args);
        cout << self->_threadname << endl;returnnullptr;}voidJoin(){pthread_join(_tid,nullptr);}private:
    pthread_t _tid;
    std::string _threadname;};intmain(){
    vector<Thread> threads;for(int i =0; i <10; i++){
        string name ="thread-"+to_string(i);
        Thread thread(name);
        threads.push_back(thread);
        threads[i].start();}for(auto&thread : threads){
        thread.Join();}return0;}

代码现象

在这里插入图片描述
可以发现,有些_threadname没有打印出来,有些打印出来了,因为加了sleep的原因,这个现象还是比较固定,容易分析的,那么原因出在哪了,没错,就是vector,vector的扩容问题。

分析代码

线程并发执行引发的vector扩容造成的线程安全问题

第一次循环

第二次循环

分析现象

在这里插入图片描述
在这里插入图片描述

来验证一下vector的扩容

只需要添加一行,std::cout<<threads.capacity()<<std::endl;

for(int i =0; i <10; i++){
        std::cout<<threads.capacity()<<std::endl;
        string name ="thread-"+to_string(i);
        Thread thread(name);
        threads.push_back(thread);
        threads[i].start();}

现象

扩容
至此,验证STL容器的vector线程不安全完成。

解决方法

这里提2种解决办法
1、先把Thread放进vector,最后再遍历vector来启动
2、进行加锁,这里的加锁也要留心,加锁不正确,仍然会导致线程安全问题

intmain(){
    vector<Thread> threads;for(int i =0; i <10; i++){
        string name ="thread-"+to_string(i);
        Thread thread(name);
        threads.push_back(thread);}for(int i =0; i <10; i++){
        threads[i].start();}for(auto&thread : threads){
        thread.Join();}return0;}

加锁的代码,注意加锁和释放锁的时机,不正确的加锁仍然会有问题

#include<iostream>#include<pthread.h>#include<string>#include<vector>#include<unistd.h>usingnamespace std;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;classThread{public:Thread(string &name):_threadname(name){}boolstart(){pthread_mutex_lock(&lock);// sleep(1); // 这里sleep是为了让现象变得固定,不加sleep,则现象就太随机,不容易画图分析int n =pthread_create(&_tid,nullptr, threadroutine,this);if(n ==0){returntrue;}returnfalse;}staticvoid*threadroutine(void*args){
        
        Thread *self =static_cast<Thread *>(args);
        cout << self->_threadname << endl;pthread_mutex_unlock(&lock);returnnullptr;}voidJoin(){pthread_join(_tid,nullptr);}private:
    pthread_t _tid;
    std::string _threadname;};intmain(){
    vector<Thread> threads;for(int i =0; i <10; i++){
        
        string name ="thread-"+to_string(i);
        Thread thread(name);pthread_mutex_lock(&lock);
        threads.push_back(thread);pthread_mutex_unlock(&lock);
        threads[i].start();}for(auto&thread : threads){
        thread.Join();}return0;}

小结

在多线程场景中,std::vector 并发访问和扩容会导致数据竞争、无效指针、内存泄漏等问题。通过该案例分析,能够能加深刻的认识到线程安全带来的危害,实验的是string,那如果是金钱呢,线程安全问题不可忽视

标签: c++ 安全 linux

本文转载自: https://blog.csdn.net/2201_75443644/article/details/143661747
版权归原作者 ღ 噫吁嚱 所有, 如有侵权,请联系我们删除。

“【C++】验证STL容器线程不安全”的评论:

还没有评论