3

This is a follow-up question to Using a thread in C++ to report progress of computations.

Suppose that I have a for loop which executes run_difficult_task() many times, and I would like to infer how far the loop has advanced. I used to write:

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

    run_difficult_task(i);

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

but the main problem with such approach is that executing run_difficult_task() might literally take forever (by being stuck in an infinite loop, etc.), so I would like to get a progress report in every k seconds by means of printing out the value of the loop variable i.

I found quite a rich literature on this site regarding object-oriented multithreading (of which I am not really familiar with) in various programming languages, but the questions I found doing this in C-style seem quite outdated. Is there a platform-independent, C11 way to do what I want? If there is not any, then I would be interested in methods working in unix and with gcc.

Note: I do not wish to run various instances of run_difficult_task in parallel (with, for example, OpenMP), but I want to run the for loop and the reporting mechanism in parallel.


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

Community
  • 1
  • 1
Matsmath
  • 1,164
  • 2
  • 21
  • 40

3 Answers3

5

Linux (and also POSIX systems) provide the alarm library call. This allows you to do something after an interval of seconds without interrupting your main thread, and without bothering with multi-threading when you don't really need it. It was very much created for use cases like yours.

antlersoft
  • 14,636
  • 4
  • 35
  • 55
  • I will certainly check this out. – Matsmath May 05 '16 at 20:08
  • Good suggestion. The OP should note, however, that approaching the problem in this way requires that `run_difficult_task()` be robust against interruption by signals. Whether that's much of a problem depends on the details of that function. – John Bollinger May 05 '16 at 20:09
  • The alternative is almost certainly to make `run_difficult_task()` communicate its progress externally somehow (message passing or somesuch). `run_difficult_task()` could also be modified to do low-overhead stores into a memory-backed file acting as a ring buffer, which would allow external instrumentation to monitor progress at runtime. Finally, one could use tools like `gdb` or `perf` to sample the process state over time. – dho May 05 '16 at 20:14
1

You can try using one thread (the worker thread) or possibly two (one that does computations and one that displays output while main is doing something else or just waiting) and some global variables (ugh).

The first thread will be your workhorse doing computations and updating some global variable. The second one (maybe simply the main thread) will then check whether this variable has changed or not and then print the stats (perhaps, that variable will hold the stats, for example, percentage).


What you can try:

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;
ForceBru
  • 43,482
  • 10
  • 63
  • 98
  • You don't necessarily need globals to implement a thread-based solution, but you do need shared variables. And if you are going to implement a solution involving shared variables, then you also need proper synchronization. In this case, that would probably mean protecting access to the shared variables via a mutex. – John Bollinger May 05 '16 at 20:13
  • If I understand you correctly, if there is only one thread, then you are actually suggesting to put the reporting mechanism (e.g., printf) *inside* `run_difficult_task()`? That does not help much. – Matsmath May 05 '16 at 20:19
  • @Matsmath, nope, you didn't understand that correctly. _worker thread_ is your `run_difficult_task`. `printf` is located '`// in main thread`' – ForceBru May 05 '16 at 20:21
  • Ah, all right then. So, to clarify, when you are saying "You can try using one thread" you actually mean "You can try using one additional (=worker) thread besides the main thread". So at least two threads. – Matsmath May 05 '16 at 20:24
  • @Matsmath, yeah. I reworded this part a bit, so you may want to take a look at the edits. – ForceBru May 05 '16 at 20:34
0

Here's a simple time based progress indicator that I've often used:

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

UPDATE:

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

No, but I've updated the example to put the progress code in a separate function, which is what I normally do in my own code.

You'll have to add calls to the progress function within run_difficult_task to get finer grain progress--this is something I also do in my own code.

But, notice that I added an elapsed time [in seconds] to the progress.

If you didn't care about that, if run_difficult_task takes longer than 2 seconds to run, there is no progress until it returns as you define it because progress is defined by incrementing i which is done by the outer loop.

For my own stuff, the progress function can handle an arbitrary number of progress indicators from an arbitrary number of worker threads.

So, if that would be of interest to you, and [say] run_difficult_task has some inner loop variables like j, k, l, these could be added to the progress. Or, whatever you wish to report on.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48