2012-02-15 156 views
0

一个类的XYZ有3个成员变量x,y,z。有[N]个XYZ对象的向量。多线程,线程间通信,同步

有3个线程A,B,C,它们可以访问vector中的任何对象和该对象的任何成员变量。

class XYZ 
{ 
public: 
double x; 
double y; 
double z; 
}; 

std ::具有N个元素的向量,其中N在整个程序中是固定的。

如何设计线程间通信以实现线程安全和最高效率,即最小的阻塞。

这里是我的一些思考过程,如果我错了,请纠正我

  1. 将向量除以更小的向量并封装到每个线程中 类,然后使用消息队列传递数据。问题 都是3个线程都可以访问矢量和对象 成员的任何地方,因此很难细分和封装。 消息队列本身需要阻塞,即当发件人添加到队列时,读取器需要被阻塞 。
  2. 使用原子库使访问原子,因此避免 阻塞。问题原子依赖于操作系统,即某些操作被认为是原子操作,在Linux下可能不是原子操作,在Windows下可能不是原子操作。
  3. 互斥,为每个成员变量添加3个互斥对象,例如mutex_x, mutex_y,mutex_z。然而,问题是互斥的不可复制,

也就是说,如果我们有一个类一样,

class XYZ_mutex 
{ 
public: 
double x; 
double y; 
double z; 
boost::mutex mutex_x; 
boost::mutex mutex_y; 
boost::mutex mutex_z; 
}; 

我们不能有XYZ_mutex的载体,因为.push_back()是一个拷贝构造函数。

谢谢。

+3

为什么要使用三个互斥量而不是一个互斥量?而你关于没有矢量的逻辑是错误的 - 你可以为你的类创建一个拷贝构造函数(当然,它不会复制互斥量,但你为什么要这样做?) – 2012-02-15 15:45:50

+0

虽然“我们不能一个XYZ_mutex矢量,因为.push_back()是一个拷贝构造函数。“是真的,你可以拥有'ZYX_mutex *'的矢量。 – Griwes 2012-02-15 15:50:29

+0

线程A,B,C对向量做了什么? – 2012-02-15 15:55:12

回答

2

您需要考虑您的程序具有哪些使用模式和一致性要求。

第一个也是最重要的使用模式是任何线程是否需要修改这些结构。如果没有,你实际上不需要任何锁定 - 只要确保在线程开始读取之前填充结构。如果线程不得不修改结构,则需要考虑一致性。你需要问自己,如果有任何限制,除了修改个人double值,该限制,当一个线程可以看到另一个线程所做的更改。

一旦你定义了这一点,就开始思考数据是否可以以任何方式在线程之间拆分,以减少线程之间的冲突 - 即使它不能完全消除,问题的答案是保留三个向量的双倍更好,一个XYZ矢量或其他组织的依赖关系,是否会有一些线程更频繁地访问某些XYZ对象,或者是否会有线程更频繁地访问x成员,而其他线程则更频繁地访问ys或zs等。

如果你不能说任何线程访问任何实例的任何成员的概率,很难说如何最好地组织它们。将它们放在堆上以便它们落入不同的缓存行中可能是个好主意。总的来说,最好的建议可能是将它们放入任何最适合您的需求的数据结构(矢量,地图,集合等),使用单个互斥体同步整个事物,编写程序和然后测试是否遇到瓶颈。

1

我会选择1(有一些变化,请参阅下文),只是因为数组中的每个项的互斥体代价太大。

因此,将您的数组分成更小的块,每个块都受互斥锁保护是一个不错的主意。然后,当线程需要访问数组的某个部分时,它可以访问另一个数据结构,该数据结构根据访问的项目所在的时间间隔为其提供需要锁定的互斥锁(例如,将索引关联到索引具有该特定时间间隔的互斥项目)。

+0

如果他能隔离访问,这可能是一个好主意。然而,如果一个线程需要访问一个部分以更新另一个部分,它将需要获得两个锁,并且避免死锁是棘手的(尽管可以完成)。 – 2012-02-15 16:03:25

1

没有一个正确的答案。其基本规则是:

  1. 试图组织的东西所以没有线程每一个需要多于一个 互斥。否则,您需要一些(通常不明显的)解决方案来避免死锁的风险。

  2. 尽量保持每个互斥量尽可能短。如果你可以组织事物,以便有n个不同的数组,每个线程只有 访问一个不同的数组,每个不同的数组只有一个类访问 ,这是最佳的,因为这意味着每个线程都可以采取行动一旦它获得了其不同阵列的所有权,就无需锁定。 (它听起来不像是这种情况,但是。)

在很大程度上将取决于线程的方式(和频率)访问向量的 元件。

最后,有几种处理 ,XYZ对象中互斥量问题的方法。最明显的是使用最近编译器,其中 支持移动语义; std::mutex是可移动的,并且可以在 std::vector中使用。如果不这样做,你可以使用boost::shared_ptr<>到 互斥量。

+0

谢谢James,经过几天的研究,我找到了使用boost :: shared_ptr的方法。这是一篇相当不错的文章。 http://www.boost.org/doc/libs/1_48_0/libs/smart_ptr/sp_techniques.html – 2607 2012-02-21 04:23:06

0

使用选项1.但也将矢量分成3部分,并允许每个线程在其块上工作,以不干扰其他线程。您始终可以使用矢量的长度来创建这些虚拟边界。哎呀,你可以让每个线程都有自己的向量。然后,当你插入到矢量中时,通过一个“负载平衡器”发送你的请求,使它插入到正确的矢量中(只是贪婪)。您也可以使用平衡器重新平衡向量,因为某个线程比其他线程慢(将项目从1个向量移动到其他线程)