多线程,线程间通信,同步

时间:2012-02-15 15:43:25

标签: c++ multithreading

一个类XYZ有3个成员变量x,y,z。有[N] XYZ对象的向量。

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

class XYZ
{
public:
double x;
double y;
double z;
};
带有N个元素的

std :: vector,其中N在整个程序中是固定的。

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

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

  1. 将矢量划分为较小的矢量并封装到每个线程中 class,然后使用消息队列来传递数据。问题 所有3个线程都可以访问向量和对象的任何位置 成员,因此难以细分和封装。 消息队列本身需要阻塞,即读者需要 发件人添加到队列时阻止。
  2. 使用原子库使访问成为原子,因此避免 阻塞。问题是原子是依赖于操作系统的,即一些 Linux下的操作被认为是原子的,可能不是原子的 视窗。
  3. Mutex,为每个成员变量添加3个互斥对象,例如mutex_x, mutex_y,mutex_z。但是,问题是互斥是不可复制的,
  4. 即,如果我们有一个类,

    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()是一个复制构造函数。

    感谢。

4 个答案:

答案 0 :(得分:2)

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

第一个也是最重要的使用模式是任何线程是否需要修改这些结构。如果没有,您实际上并不需要任何锁定 - 只需确保在线程开始读取之前填充结构。

如果线程必须修改结构,则需要考虑一致性。您需要问自己,除了修改单个double值之外是否存在任何约束,当一个线程可以看到另一个线程所做的更改时,该限制将被限制。

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

如果您无法透露任何线程访问任何实例的任何成员的可能性,那么很难说如何最好地组织它们。将它们放在堆上以使它们落在不同的缓存行中可能是个好主意。

总的来说,最好的建议可能是首先将它们放入任何最适合您需求的数据结构(矢量,地图,设置等),使用单个互斥体同步整个事物,编写程序然后测试你是否遇到瓶颈。

答案 1 :(得分:1)

我会选择选项1(稍作修改,见下文),只是因为为数组中的每个项目添加一个互斥锁成本太高。

因此,将数组划分为较小的块是个好主意,每个块都由互斥锁保护。然后,当一个线程需要访问该数组的某个部分时,它可以访问另一个数据结构,该数据结构为其提供需要锁定的互斥锁,具体取决于所访问项的间隔(例如,关联索引的哈希表)具有该特定间隔的互斥锁的项目。)

答案 2 :(得分:1)

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

  1. 尝试组织事物,以便每个线程都不需要多个线程 互斥。否则,您需要一些(通常是非显而易见的)解决方案来避免 发生僵局的风险。

  2. 尽量保持每个互斥锁的时间尽可能短。如果你可以的话 组织事物,以便有n个不同的数组,每个线程只有 访问单个不同的数组,每个不同的数组只是 由单个类访问,这是最佳的,因为它意味着每个 一旦获得了对它的所有权,线程就可以在没有锁的情况下行动 不同的阵列。 (然而,听起来并非如此。)

  3. 很多将取决于线程访问的方式(以及频率) 向量的元素。

    最后,有几种方法可以解决互斥锁的问题 XYZ对象。最明显的是使用最近的编译器 支持移动语义; std::mutex是可移动的,可用于 std::vector。如果不这样做,你可以使用boost::shared_ptr<> 互斥。

答案 3 :(得分:0)

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