C++编程 –安全并发访问容器元素


C++ 安全并发访问容器元素

2014-9-24 flyfish
标准库STL的vector, deque, list等等不是线程安全的
例如 线程1正在使用迭代器(iterator)读vector
线程2正在对该vector进行插入操作,使vector重新分配内存,这样就造成线程1中的迭代器失效

STL的容器
多个线程读是安全的,在读的过程中,不能对容器有任何写入操作
多个线程可以同时对不同的容器做写入操作。
不能指望任何STL实现来解决线程难题,必须手动做同步控制.

《C++ 设计新思维》 下载见

C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码

读C++ Primer 之构造函数陷阱

读C++ Primer 之智能指针

读C++ Primer 之句柄类

将C语言梳理一下,分布在以下10个章节中:

  1. Linux-C成长之路(一):Linux下C编程概要
  2. Linux-C成长之路(二):基本数据类型
  3. Linux-C成长之路(三):基本IO函数操作
  4. Linux-C成长之路(四):运算符
  5. Linux-C成长之路(五):控制流
  6. Linux-C成长之路(六):函数要义
  7. Linux-C成长之路(七):数组与指针
  8. Linux-C成长之路(八):存储类,动态内存
  9. Linux-C成长之路(九):复合数据类型
  10. Linux-C成长之路(十):其他高级议题



方案1 对vector进行加锁处理

effective STL给出的Lock框架

template<typename Container> //一个为容器获取和释放互斥体的模板 
class Lock
{ //框架;其中的很多细节被省略了 
public:
 Lock(const Container& container) :c(container)
 { 
  getMutexFor(c);
  //在构造函数中获取互斥体
 }
 ~Lock()
 { 
  releaseMutexFor(c);
  //在析构函数中释放它
 }
private: const Container& c;
}; 

如果需要实现工业强度,需要做更多的工作。


方案2 微软的Parallel Patterns Library (PPL)


看MSDN
PPL 提供的功能

1 Task Parallelism: a mechanism to execute several work items (tasks) in parallel
任务并行:一种并行执行若干工作项(任务)的机制

2 Parallel algorithms: generic algorithms that act on collections of data in parallel
并行算法:并行作用于数据集合的泛型算法

3 Parallel containers and objects: generic container types that provide safe concurrent access to their elements
并行容器和对象:提供对其元素的安全并发访问的泛型容器类型


示例是对斐波那契数列(Fibonacci)的顺序计算和并行计算的比较

顺序计算是
使用 STL std::for_each 算法
结果存储在 std::vector 对象中。

并行计算是
使用 PPL Concurrency::parallel_for_each 算法
结果存储在 Concurrency::concurrent_vector 对象中。

// parallel-fibonacci.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <concurrent_vector.h>
#include <array>
#include <vector>
#include <tuple>
#include <algorithm>
#include <iostream>


using namespace Concurrency;
using namespace std;


// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
  __int64 begin = GetTickCount();
  f();
  return GetTickCount() - begin;
}


// Computes the nth Fibonacci number.
int fibonacci(int n)
{
  if(n < 2)
      return n;
  return fibonacci(n-1) + fibonacci(n-2);
}


int wmain()
{
  __int64 elapsed;


  // An array of Fibonacci numbers to compute.
  array<int, 4> a = { 24, 26, 41, 42 };


  // The results of the serial computation.
  vector<tuple<int,int>> results1;


  // The results of the parallel computation.
  concurrent_vector<tuple<int,int>> results2;


  // Use the for_each algorithm to compute the results serially.
  elapsed = time_call([&]
  {
      for_each (a.begin(), a.end(), [&](int n) {
        results1.push_back(make_tuple(n, fibonacci(n)));
      });
  }); 
  wcout << L"serial time: " << elapsed << L" ms" << endl;


  // Use the parallel_for_each algorithm to perform the same task.
  elapsed = time_call([&]
  {
      parallel_for_each (a.begin(), a.end(), [&](int n) {
        results2.push_back(make_tuple(n, fibonacci(n)));
      });


      // Because parallel_for_each acts concurrently, the results do not
      // have a pre-determined order. Sort the concurrent_vector object
      // so that the results match the serial version.
      sort(results2.begin(), results2.end());
  }); 
  wcout << L"parallel time: " << elapsed << L" ms" << endl << endl;


  // Print the results.
  for_each (results2.begin(), results2.end(), [](tuple<int,int>& pair) {
      wcout << L"fib(" << get<0>(pair) << L"): " << get<1>(pair) << endl;
  });
}

命名空间Concurrency首字母大写,一般命名空间全是小写。

本文永久更新链接地址:

  • 1
  • 2
  • 下一页

相关内容