c++中的有序多线程输出

Ordered multithreading output in c++

本文关键字:多线程 输出 c++      更新时间:2023-10-16

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

   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();
}

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

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_back执行重叠,它可能会覆盖同一个元素,或者它可能会重新分配移动所有元素存储位置的数组。)

您可以通过以下几种方法来处理此问题。如果你不在乎它们完成的顺序,只在乎结果的顺序,那么推送一个带有任务id及其结果的对象,然后按任务id对对象进行排序,并在所有操作完成后打印。

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

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

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

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

附带说明,如果你想在多线程世界中使用push_back,我会使用list而不是vector,list将保留除要删除的元素之外的所有元素的迭代器。。。

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