2

我在测试类中有 4 个函数:

void Test::A()
{
    boost::lock_guard<boost::mutex> lock(mutex);
    cout << "A!" << endl;
}

void Test::B()
{
    boost::lock_guard<boost::mutex> lock(mutex);
    cout << "B!" << endl;
}

void Test::C()
{
    boost::lock_guard<boost::mutex> lock(mutex);
    cout << "C!" << endl;
}

void Test::D()
{
    boost::lock_guard<boost::mutex> lock(mutex);
    cout << "D!" << endl;
}

如果我按字母顺序调用,一遍又一Test::A遍地Test::D循环并将它们绑定到 boost thread_pool,它在大多数情况下都可以正常工作。但是,有时 cout 语句会乱序打印。所以我可能会看到 ABCDABCDABCDAB D C。据我了解,这与 thread_pool 何时获得新线程有关,我无法控制它们被调用的顺序。

我的问题是我需要按顺序调用 C() 和 D()(当需要调用它们时),并且不关心 A() 和 B() 相对于彼此和 C() 的顺序和D()。因此,我现在不是通过 thread_pool 调用 C 和 D,而是通过主进程调用它,保留所有互斥锁。当我尝试再次调用循环中的所有函数时,程序在 C 中的 cout 语句之前挂起。我很困惑为什么会这样。我可以在主进程和线程之间没有互斥锁吗?

尽管这些函数本质上很简单,但我无法将 C 和 D 的逻辑结合起来,因为这些函数最终会升级为基于事件的函数。一遍又一遍地调用它们的循环只是一个模拟现实生活事件的虚拟循环。D 总是在 C 之后被调用,但它可能会或可能不会被调用。

例如:

A B C D

ABCCD

广告

ABCCC

4

4 回答 4

2

如果 C 和 D 可以由单独的事件触发(即不能在同一个线程中顺序调用它们),但 D 不能在 C 之前执行,则需要使用条件变量或其他一些同步方式(也许是信号量)。

由于您已经在使用 boost,我建议您查看Boost Condition Variables

于 2013-08-13T13:55:15.600 回答
1

如果要保持执行顺序,请查看信号量。锁是先进先出的,所以无论哪个线程首先获得锁,都会先执行。要确保在 D 之前调用 C,请执行以下操作:

C : increment semaphore by 1
D : decrement semaphore by 1

如果信号量从 0 开始,则 D 只能在信号量为 1 时递减信号量(已由 C 递增)。对于这种情况,您可以使用二进制信号量。可能的值为 0 或 1。

于 2013-08-16T21:19:57.503 回答
1

这是完全正常的。当您启动两个线程池线程时,首先是 A,然后是 B,则无法保证 A 在 B 之前到达 cout 语句。这只是可能的。您创建的错误称为“线程竞争”,这是代码中非常常见的错误,它使用线程并且众所周知难以诊断和修复。

这些线程按照自己的节奏运行。如果操作系统抢占了 A 而不是 B,例如当它想允许另一个进程中的另一个线程运行时,那么 B 肯定会抢在 A 之前并首先到达 cout 语句。确保这些 cout 语句严格按顺序执行的唯一简单方法是使用一个线程。

于 2013-08-13T13:18:24.233 回答
0

您可能有一个 fifo 队列来排序 C/D 事件并处理并删除该队列中的第一个元素,如果它有结果(可能是线程 E)。如果线程 C 和 D 可能相互干扰,则只制作一个线程 CD。

如果 C 事件实际上触发了 D 事件,您可能会考虑使用并行管道 C->D。

于 2013-08-13T13:37:37.630 回答