2

在这个简单的例子中如何保证

   a->push_back(i)

以线程启动的顺序发生?所以内容将是{1,2,3}。

#include <vector>
#include <thread>

void do_stuf(int i,std::vector<int> * a)
{
    //do very long stuff
    a->push_back(i);
}


int main()
{
    std::vector<int> tmp;
    std::thread t1(do_stuf,1,&tmp);
    std::thread t2(do_stuf,2,&tmp);
    std::thread t3(do_stuf,3,&tmp);

    t1.join();
    t2.join();
    t3.join();
}
4

5 回答 5

5

一种方法是向线程传递一个指针或引用,指向您希望它们存储结果的位置(并确保它在线程生命周期内保持分配),如下所示:

void do_stuf(int i, int* a)
{
    //do very long stuff
    *a = i;
}


int main()
{
    std::vector<int> tmp(3);
    std::thread t1(do_stuf,1,&tmp[0]);
    std::thread t2(do_stuf,2,&tmp[1]);
    std::thread t3(do_stuf,3,&tmp[2]);

    t1.join();
    t2.join();
    t3.join();
}

从您的示例中不清楚您要实现什么,但是您是否看过 std::promise 和 std::future 并弄清楚它们的作用?他们可能是你想要的。

(在这种情况下,vector::push_back 的问题在于它不是线程安全的。如果两个 push_backs 执行重叠,它可能会覆盖相同的元素,或者它可能会重新分配数组以移动所有元素的存储位置。)

于 2012-07-31T18:49:32.457 回答
0

对不起,我错过了“//做很长的事情”。如果在长动作结束时有一个特殊动作必须以特定顺序完成,您可以简单地将该代码放在 3 个线程的连接后面。

如果必须由该特定线程执行此操作,则可以使用受互斥锁和条件变量保护的共享计数器来表示该计数器已更改。更改计数器时,必须通知所有服务员,因为需要唤醒特定线程。在函数结束时,函数等待计数器具有特定于线程的值。第一个线程正在等待初始值,执行它的操作,递增计数器。第二个线程正在等待计数器成为第二个值等。

于 2012-07-31T18:45:31.080 回答
0

你可以通过几种方式来解决这个问题。如果你不关心它们完成的顺序,只关心结果的顺序,推送一个带有任务 ID 及其结果的对象,然后按任务 ID 对对象进行排序,并在所有完成后打印。

如果您确实希望他们在上一个任务完成之前不报告,您需要等待上一个任务。

于 2012-07-31T18:42:20.693 回答
-1

当线程长进程按照调度顺序完成时,您可以有一个回调来“同步”推回。

旁注,如果您希望在多线程世界中使用 push_back,我将使用列表而不是向量,列表将保留除被删除元素之外的所有内容的迭代器...

于 2012-07-31T18:42:15.303 回答
-1

正如所写,插入可以任意排序。为了确保您订购所需的订单,您基本上需要一个票务系统,其中线程睡眠/旋转直到请求他们的票号。在高层次上,这意味着您向每个线程传递了一条额外的信息(它的票号),具有一个全局共享值,即请求的票号 ID,并且线程代码具有一些确保不执行插入的代码直到全局 ID 等于本地编号。

于 2012-07-31T18:42:47.650 回答