C++多线程:从多线程中最快的线程检测返回值

rryofs0p  于 2022-09-19  发布在  Linux
关注(0)|答案(1)|浏览(262)

详情:

在下面的程序中,多个threads(本例中为简单起见只有2个)监听从函数返回的相同的值66,遵循两个函数中产生结果66的一些逻辑。

threads使用async66的值使用futures返回。使用while循环来尝试连续检查线程1和线程2的status,以检查它们中的任何一个是否已经完成,在这种情况下,然后从任何一个线程获取最快的结果并在某些计算中使用。

目标:

1.在两个threads中,检测其中哪一个最先返回66的值
1.只要一个线程返回66(不管另一个线程是否已经完成),返回值就在main()中可用,以便对其执行一些进一步的简单运算
1.如果一个线程返回66,并对main()中的这个值执行算术运算,然后另一个线程随后也传递66,则不应在任何计算中使用第二个返回值

**请注意:**在决定发布这个问题之前,我们已经咨询了以下资源:

1.How to check if thread has finished work in C++11 and above?
1.Using Multithreading two threads return same value with different inputs?
1.后台加载的C++线程
1.Future returned by a function
1.Start multiple threads and wait only for one to finish to obtain results

问题和当前产出:

目前,即使function1中的代码速度慢得多(例如,function1中有1000次迭代的for循环和function1中有10次迭代的for循环),程序始终输出第一个完成的threadrf1。这让我相信,我可能引入了某种blocking行为?

节目尝试:


# include <future>

    #include <iostream>
    #include "unistd.h"

    double function1() {

        // Logic to retrieve _value
        // ...
        double _value = 66;

        return _value;
    }

    double function2() {
        // Logic to retrieve _value
        // ...
        double _value = 66;

        return _value;
    }

    int main() {

        double ret_value = 0;

        auto rf1 = std::async(std::launch::async, function1);
        auto status1 = rf1.wait_for(std::chrono::nanoseconds(1));

        auto rf2 = std::async(std::launch::async, function2);
        auto status2 = rf2.wait_for(std::chrono::nanoseconds(1));

        while (true) {

            if (status1 == std::future_status::ready) {
                std::cout << "RF1 FINISHED FIRST" << std::endl;

                // No longer need returned val from 2nd thread.
                // Get result from 1st thread
                ret_value = rf1.get();
                break;
            }
            else if (status2 == std::future_status::ready) {
                std::cout << "RF2 FINISHED FIRST" << std::endl;

                // No longer need returned val from 1st thread.
                // Get result from 2nd thread
                ret_value = rf2.get();
                break;
            }

            else if (status1 != std::future_status::ready) {

                // RF1 not finished yet
                status1 = rf1.wait_for(std::chrono::nanoseconds(1));
            }
            else if (status2 != std::future_status::ready) {

                // RF2 not finished yet
                status2 = rf2.wait_for(std::chrono::nanoseconds(1));
            }
        }

        // Do some calculations on the quickest
        // returned value
        double some_value = ret_value + 40;

        return 0;
    }

问题:

**Q1.**是否可以通过任何方式修改程序以检测返回最快的thread,以便在main()中使用66的返回值进行进一步计算?

q2.while循环是否引入了任何类型的blocking行为?

如果任何人能够提供建议或指出一些有助于解决这一困境的资源,我们将不胜感激。到目前为止,找到与此场景完全匹配的multithreading文档一直是一个挑战。

编辑:

根据@jxh提供的有用答案,指示WHILE循环继续等待的else if条件已被删除,如下所示。

此外,还向function1function2添加了一些逻辑,以确定哪一个将最先完成。如代码中所示,function1具有98迭代,function2具有100迭代,但输出仍然显示function2已首先完成:


# include <future>

# include <iostream>

# include "unistd.h"

double function1() {

    // Logic to retrieve _value
    for (int i = 0; i < 98; i++) {
        std::cout << std::endl;
    }
    double _value = 66;

    return _value;
}

double function2() {

    // Logic to retrieve _value
    for (int i = 0; i < 100; i++) {
        std::cout << std::endl;
    }
    double _value = 66;

    return _value;
}

int main() {

    double ret_value = 0;

    auto rf1 = std::async(std::launch::async, function1);
    auto status1 = rf1.wait_for(std::chrono::nanoseconds(1));

    auto rf2 = std::async(std::launch::async, function2);
    auto status2 = rf2.wait_for(std::chrono::nanoseconds(1));

    while (true) {

        if (status1 == std::future_status::ready) {
            std::cout << "RF1 FINISHED FIRST" << std::endl;

            // No longer need returned val from 2nd thread.
            // Get result from 1st thread
            ret_value = rf1.get();
            break;
        }
        else if (status2 == std::future_status::ready) {
            std::cout << "RF2 FINISHED FIRST" << std::endl;

            // No longer need returned val from 1st thread.
            // Get result from 2nd thread
            ret_value = rf2.get();
            break;
        }

        status1 = rf1.wait_for(std::chrono::nanoseconds(1));
        status2 = rf2.wait_for(std::chrono::nanoseconds(1));

    }

    // Do some calculations on the quickest
    // returned value
    double some_value = ret_value + 40;

    return 0;
}
vojdkbi0

vojdkbi01#

while内部代码中的逻辑将始终调用rf1.wait_for(),直到其状态为Ready。

由于您的ready检查将break退出循环,因此您不需要使用else if来决定是否进行进一步的等待。只需再做两次等待,就像进入while之前一样。

status1 = rf1.wait_for(std::chrono::nanoseconds(1));
    status2 = rf2.wait_for(std::chrono::nanoseconds(1));

您已经更新了问题,并且更改了被调用函数的行为,而不是原来的行为。让我们笼统地谈一下这个问题,而不是讨论这些变化。

  • 您正在尝试以纳秒分辨率等待。
  • 您的线程与当前实现的线程仅相差相当小的循环体的2次迭代。
  • 编译器可以自由地以这样一种方式优化代码,即函数可以在几乎相同的时间内执行。
  • 因此,对期货进行1纳秒的来回窥视并不是确定哪个期货实际上最先返回的可靠方式。

要解决接近终点,你可以使用蜂鸣器,就像他们在游戏节目中所做的那样。最先发出嗡嗡声的是一个明确的信号。我们可以用管道模拟蜂鸣器,而不是尝试实现真正的蜂鸣器。并且,该函数通过向管道写入一个值来嗡嗡作响。

int photo_finish[2];

double function1() {
    int id = 1;
    //...
    write(photo_finish[1], &id, sizeof(id));
    double _value = 66;
    return _value;
}

double function2() {
    int id = 2;
    //...
    write(photo_finish[1], &id, sizeof(id));
    double _value = 66;
    return _value;
}

然后,等待代码从管道中读取,并观察值。该值指示哪个函数最先完成,因此代码然后等待适当的将来来获取该值。

pipe(photo_finish);

    auto rf1 = std::async(std::launch::async, function1);
    auto rf2 = std::async(std::launch::async, function2);

    int id = 0;
    read(photo_finish[0], &id, sizeof(id));

    if (id == 1) {
        auto status1 = rf1.wait();
        //...
    } else if (id == 2) {
        auto status2 = rf2.wait();
        //...
    }

请注意,为简洁起见,示例代码省略了错误处理。

相关问题