UNIX(多线程):24---哪些STL容器是线程安全的

        在日常C++开发,少不了和STL,多线程打交道,那么在多线程下,哪些容器时线程安全的,那些不是?

         好,这里就举一个简单的例子,我们先看看vector容器,相信你能看出一些问题:



#include <iostream>
#include <string>
#include <algorithm>
#include <thread>
#include <vector>


using namespace std;
vector<int> vec;
void myprint(void) {
        while(1){
        for(auto it = vec.begin(); it != vec.end(); it++){
                *it = 65535;
                cout << "输出:"<< *it<< endl;
        }
        vec.push_back(1);
        vec.push_back(1);
        vec.push_back(1);
        cout<<"插入数据"<<endl;
//      sleep(1);
        }
        return;
 }
int main()
{
        vec.push_back(0);
        thread my_threads(myprint);


        while(true){
                vec.push_back(1);
                vec.clear();
        }
        my_threads.join();
        std::cout << "主线程结束" << std::endl;
        return 0;
}


 

g++ -g -o t t.cpp -lpthread

好了,这个程序不够持久,没能挺过2秒,结果就dump了

我们来跟踪下看到底是怎么回事:

首先崩溃时,子线程在vec.push_back(1); 父线程在vec.clear();

这两个操作都是对vec进行写操作,产生的这种写操作没有加锁,那么就会出现dump。其他的容器也是类似的,大家也可以尝试去写一些代码验证。

一般说来,stl对于多线程的支持仅限于下列两点: 

1.多个读取者是安全的。即多个线程可以同时读取一个容器中的内容。即此时多个线程调用 容器的不涉及到写的接口都可以 eg find, begin, end 等.

2.对不同容器的多个写入者是安全的。即多个线程对不同容器的同时写入合法。但是对于同一容器当有线程写,有线程读时,如何保证正确? 需要程序员自己来控制,比如:线程A读容器某一项时,线程B正在移除该项。这会导致一下无法预知的错误。通常的解决方式是用开销较小的临界区(CRITICAL_SECTION)来做同步。

以下列方式同步基本上可以做到线程安全的容器(就是在有写操作的情况下仍能保证安全)。

  1.每次调用容器的成员函数的期间需要锁定。

  2.每个容器容器返回迭代器的生存期需要锁定。

  3.每个容器在调用算法的执行期需要锁定。

当你调用stl的一些方法返回一个iterator, 如果有别的线程正在修改这个容器, 你的iterator就变得无效了, 再用这个iterator行为就可能出问题. 比如map者在find()函数内部, 会访问到map内部的红黑树的数据结构, 而这个红黑树是有可能被别的线程调整的(比如别的现在往map中插入一个不存在的记录). 所以, 是危险的.

 

  为了效率,没有给所有操作加锁。不同线程同时读同一容器对象没关系,不同线程同时写不同的容器对象没关系。但不能同时又读又写同一容器对象的。

因此,多线程要同时读写时,还是要自己加锁。

相关推荐
实付 39.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值