C中的工作分配算法(do while issue)

Work distribution algorithm in C (do while issue)

所以我正在尝试开发一种算法来在线程之间平均分配工作,但它有点独特。正在完成的工作是文件比较,我们有一个文件列表(比方说 10 个文件)。我们不想将文件 1 与文件 1 进行比较,因此每个文件都会跳过自身比较。文件 1 会将自己与文件 2 到 10 进行比较,文件 2 会将自己与文件 3 到文件 10 进行比较,依此类推。因此,当我们在文件比较列表中向下移动时,文件比较的数量会下降。这是我遇到问题的小片段(特别是 do-while 循环)

// Get first pass file chunks
printf("Split approximation: ");
for (int i = 0; i < num_threads; i++)
{
    file_chunks[i] = (int)floor((double)num_file_compares / (double)num_threads);
    printf("%d ", file_chunks[i]);
}
printf("\n");

// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++)
{
    file_chunk_sum = file_chunk_sum + file_chunks[i];
}
append_count = num_file_compares - file_chunk_sum;
printf("Need to append last %d\n", append_count);

append_index = num_threads;
do
{
    printf("im in the do while...\n");
    printf("append count is: %d\n", append_count);
    printf("why am i here?\n");
    append_index = append_index - 1;
    file_chunks[append_index] = file_chunks[append_index] + 1;
    append_count = append_count - 1;
} while (append_count > 0);

printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
    printf("%d ", file_chunks[i]);
}
printf("\n");

对于 20 个文件(190 次文件比较)和 5 个线程的输入,拆分近似将是每个线程 38 个文件比较的均匀拆分。 append 计数为 0,但它仍然跳入 do-while 循环。知道为什么吗?

那些printf的输出是

Number of files: 20
Number of threads: 5
Number of file compares: 190
Split approximation: 38 38 38 38 38
Need to append last 0
im in the do while...
append count is: 0
why am i here?
Final split: 38 38 38 38 39

A 'do while' 总是至少执行一次。如果您不希望它以这种方式运行,请尝试使用常规 'while'.

"do while" C 中的循环总是至少执行一次,你想要的是 "while" 循环

而不是使用 do...while,您只想使用 while。这会在循环顶部而不是底部执行检查。

while (append_count > 0)
{
    printf("im in the while...\n");
    printf("append count is: %d\n", append_count);
    printf("why am i here?\n");
    append_index = append_index - 1;
    file_chunks[append_index] = file_chunks[append_index] + 1;
    append_count = append_count - 1;
}

我从一条评论中了解到您已经习惯了 Fortran。以下是如何用更像 C 的 C 编写代码:

// Get first pass file chunks
printf("Split approximation: ");   // fputs("...", stdout);  is a good choice for non-formatted output, but it's clunkier to write.
// puts() confusingly tacks on a newline while fputs() doesn't, so puts(s) *isn't* just fputs(s, stdout).
// Every time you use printf, remember that the first argument is being parsed as a format string, so you have to make sure you don't use a % in it, unless you write printf("%s", "...")


for (int i = 0; i < num_threads; i++)
{
// opening brace on a line by itself is a waste of space, IMO, except for the first line of a function.
// but it's better to be consistent than to use your personal favourite style.

    file_chunks[i] = num_file_compares / num_threads;   // what's wrong with integer division here?  I think this rounds the same as your old // (int)floor((double)num_file_compares / (double)num_threads);
    printf("%d ", file_chunks[i]);
}
putchar('\n');   // here we can use a lighter-weight i/o function

int file_chunk_sum = 0;  // don't forget to initialize your variables.  And in C99 (or C++), many people prefer to declare them near where they're used instead of in a big block at the top of a function.
// Adjust file chunks to contain all files
for (int i = 0; i < num_threads; i++)  // don't use a loop to do this: see below
{
    file_chunk_sum += file_chunks[i];   // += saves human readers of your code from having to notice that it's the same variable on both sides of the =
}
append_count = num_file_compares - file_chunk_sum;
/* or you could have started with int append_count = num_f_c; and subtracted f_c[i] in the loop
 * or instead of summing, you could just take advantage of the fact that every f_c[i] has the same known value.
 * integer multiply FTW.
 * or even just make use of the remainder from your integer division and save the multiply.  (x86 at least computes remainders at the same time as dividend, so % is free if you're already doing /.)
 */
// append_count = num_file_compares - (file_chunks[0] * num_threads);

// append_count = num_file_compares % num_threads;  // or remainder

printf("Need to append last %d\n", append_count);

// append_index = num_threads;  // make this a loop variable if you like.  Some people would consider packing too much stuff into a for loop to be less readable
// actually, we can simplify the loop a *lot* by getting rid of unneeded variables.  Adjust if desired to still put the remainder counts on the later indices, rather than earlier.

for (int i=append_count ; i > 0 ; i--)
{
    // count downwards to print a descending count, same as your old code
    printf("I'm in the append loop...\n"  // nobody like "im" instead of I'm.
           "append count is: %d\n"
           "why am i here?\n", append_count);
        /* string literals concatenate automatically.
         * Writing multi-line string constants this way is generally preferred
         * to having literal newlines inside double-quotes.  That can lead to problems with line endings (Unix lf vs. DOS cr/lf vs. Mac cr).
         */
    file_chunks[i]++;   // Much easier to read ++ when using long variable names.
}

printf("Final split: ");
for (int i = 0; i < num_threads; i++)
{
    printf("%d ", file_chunks[i]);
}
putchar('\n');