报告计算进度的 C 方法是什么?

What is the C way to report progress of computation?

这是 Using a thread in C++ to report progress of computations 的后续问题。

假设我有一个 for 循环执行了 run_difficult_task() 很多次,我想推断循环进行了多远。我曾经写过:

int i;
for (i=0; i < 10000; ++i) {

    run_difficult_task(i);

    if (i % 100 == 0) {
    printf("i = %d\n", i);
    }
}

但这种方法的主要问题是执行 run_difficult_task() 可能 字面意思 永远(陷入无限循环等),所以我会喜欢通过打印循环变量 i.

的值每 k 秒获得一次进度报告

我在这个网站上发现了相当丰富的关于各种编程语言的面向对象多线程(我不太熟悉)的文献,但是我发现用 C 风格做的问题似乎已经过时了。是否有独立于平台的 C11 方式来做我想做的事?如果没有,那么我会对在 unix 和 gcc 中工作的方法感兴趣。

注意:我希望运行并行run_difficult_task的各种实例(例如OpenMP),但我想 运行 for 循环和报告机制并行。


相关:How to "multithread" C code and How do I start threads in plain C?

Linux(以及 POSIX 系统)提供 alarm 库调用。这使您可以在几秒钟后执行某些操作,而不会中断您的主线程,并且在您真正不需要多线程时也不必费心。它非常适合像您这样的用例。

您可以尝试使用一个线程(工作线程)或两个线程(一个执行计算,一个显示输出,而 main 正在执行其他操作或只是等待)和一些全局变量 (ugh)。

第一个线程将是您进行计算和更新一些全局变量的主力。第二个(可能只是主线程)将检查此变量是否已更改,然后打印统计信息(也许该变量将保存统计信息,例如百分比)。


你可以尝试什么:

int ping = 0, working = 0, data;

// in main thread 
for (/* something */){
    // spawn worker thread
    while (working) {
        if (ping) printf("%d\n", data), ping = 0;
    }
}

// in worker thread
working = 1;
while (/* something */) {
    // do a lot of computations 
    if (/* some condition */) {
        if (! ping) {
            data = /* data */
            ping = 1;
        }
    }
}
working = 0;

这是我经常使用的一个简单的基于时间的进度指示器:

void
progress(int i)
{
    time_t tvnow;
    static time_t tvlast;
    static time_t tvbeg;

    if (tvbeg == 0) {
        tvbeg = time(NULL);
        tvlast = tvbeg - 2;
    }

    tvnow = time(NULL);
    if ((tvnow - tvlast) >= 1) {
        printf("\r%ld: i = %d",tvnow - tvbeg,i);
        fflush(stdoout);
        tvlast = tvnow;
    }
}

int i;
for (i=0; i < 10000; ++i) {
    run_difficult_task(i);
    progress(i);
}

更新:

Does this update if run_difficult_task(i) runs for longer than 2seconds?

不,但我更新了示例,将进度代码放在一个单独的函数中,这是我通常在自己的代码中所做的。

您必须在 run_difficult_task 中添加对进度函数的调用以获得更细粒度的进度——这也是我在自己的代码中所做的事情。

但是,请注意我在进度中添加了经过的时间 [以秒为单位]。

如果你没有关心这个,如果run_difficult_task到运行需要超过2秒,那么没有 progress until it returns as you define it 因为进度是通过递增 i 来定义的由外循环完成。

对于我自己的东西,进度函数可以处理来自任意数量的工作线程的任意数量的进度指示器。

所以,如果您对此感兴趣,并且 [say] run_difficult_task 有一些内部循环变量,例如 jkl,这些可以添加到进度中。或者,无论想报告什么。