【问题标题】:c++ multithreading shared resourcesc++多线程共享资源
【发布时间】:2013-06-30 23:19:51
【问题描述】:

我正在尝试使用 boost 库对一段代码进行多线程处理。问题是每个线程都必须访问和修改几个全局变量。我正在使用互斥锁来锁定共享资源,但程序最终会花费更多时间而不是多线程。有关如何优化共享访问的任何建议?

非常感谢!

在下面的示例中,*choose_ecount* 变量必须被锁定,并且我不能将它从循环中取出并锁定它以仅在循环结束时进行更新,因为它需要最新的值里面函数。

for(int sidx = startStep; sidx <= endStep && sidx < d.sents[lang].size(); sidx ++){
    sentence s = d.sents[lang][sidx];
    int senlen = s.words.size();
    int end_symb = s.words[senlen-1].pos;

    inside(s, lbeta);
    outside(s,lbeta, lalpha);
    long double sen_prob = lbeta[senlen-1][F][NO][0][senlen-1];

    if (lambda[0] == 0){
        mtx_.lock();
        d.sents[lang][sidx].prob = sen_prob;
        mtx_.unlock();
    }

    for(int size = 1; size <= senlen; size++)
        for(int i = 0; i <= senlen - size ; i++)
        {
            int j = i + size - 1;
            for(int k = i; k < j; k++)
            {
                int hidx = i;   int head = s.words[hidx].pos;
                for(int r = k+1; r <=j; r++)
                {
                    int aidx = r;   int arg  = s.words[aidx].pos;
                        mtx_.lock();
                    for(int kids = ONE; kids <= MAX; kids++)
                    {
                        long double num = lalpha[hidx][R][kids][i][j] * get_choose_prob(s, hidx, aidx) *
                                lbeta[hidx][R][kids - 1][i][k] * lbeta[aidx][F][NO][k+1][j];
                        long double gen_right_prob = (num / sen_prob);

                        choose_ecount[lang][head][arg] += gen_right_prob; //LOCK
                        order_ecount[lang][head][arg][RIGHT] += gen_right_prob; //LOCK
                    }
                        mtx_.unlock();
                }

}

【问题讨论】:

  • 不是没有看到一些代码...
  • 你能把 mutext 从最里面的循环中拿出来并向上移动一个级别吗?
  • 是的。这有点帮助。
  • 下一个问题是您是否可以将互斥锁/解锁更多级别移动到围绕 for (int size = ... 循环。看来您进行初始化然后快速循环事情然后循环回来,做更多的初始化,然后再次运行循环。此外,很高兴知道函数 get_choose_prob 是如何使用它的参数和任何全局变量来知道它是否正在做一些有副作用的事情,尤其是变量 s。

标签: c++ multithreading boost


【解决方案1】:

从您发布的代码中,我只能看到写入 choose_ecount 和 order_ecount。那么为什么不使用本地每个线程缓冲区来计算总和,然后在最外层循环之后将它们相加并只同步这个操作呢?

编辑: 如果您需要访问choose_ecount 的中间值,您如何确保存在正确的中间值?一个线程可能同时完成了其循环的 2 次迭代,同时在另一个线程中产生不同的结果。

听起来您需要为计算使用屏障。

【讨论】:

    【解决方案2】:

    在内部循环中使用互斥锁不太可能获得可接受的性能。并发编程很困难,不仅对程序员,对计算机也是如此。现代 CPU 的很大一部分性能来自能够将代码块视为独立于外部数据的序列。对单线程执行有效的算法通常不适合多线程执行。

    你可能想看看boost::atomic,它可以提供无锁同步,但是原子操作所需的内存屏障仍然不是免费的,所以你可能仍然会遇到问题,你可能不得不重新考虑你的算法。

    【讨论】:

      【解决方案3】:

      我猜您将完整的问题分成从startStependStep 的块,以便由每个线程处理。

      由于您在那里锁定了mutex,因此您有效地序列化了所有线程: 您将问题分成一些块,这些块按顺序处理,但未指定顺序。 这是你唯一得到的就是执行多线程的开销。

      由于您在doubles 上进行操作,因此您不能选择使用原子操作:它们通常仅用于整数类型。

      唯一可能的解决方案是遵循 Kratz 的建议,为每个线程创建一个 choose_ecountorder_ecount 的副本,并在线程完成后将它们减少为一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多