【问题标题】:Pthreads program produces wrong outputs and correct outputs sometimesPthreads 程序有时会产生错误的输出和正确的输出
【发布时间】:2015-11-02 00:53:46
【问题描述】:

我正在学习使用 Pthreads 进行并行编程。我写了以下简单的程序作为尝试。它从标准输入中获取两个向量(用户将长度指定为命令行参数),然后将它们相加、相减、逐元素相乘并逐元素除法,方法是为这四个向量的每个操作创建一个线程。问题是有时代码可以正常工作,当我再次使用相同的输入时,它只会打印零。

为什么会这样?

我在虚拟机上使用 Ubuntu 14.04。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define loop(i, n) for (i = 0; i < n; i++)

int thread_count, n;
int *a;
int *b;
int** results; // holds the four output vectors
void* math(void* opl);


int main(int argc, char* argv[]){
    int thread = 0, i;
    pthread_t* thread_handles;

    n = strtol(argv[1], NULL, 10);

    results = malloc(4 * sizeof(int*));
    a = malloc(n * sizeof(int));
    b = malloc(n * sizeof(int));

    loop(i, n)
        scanf("%d", a + i);

    loop(i, n)
        scanf("%d", b + i);

    thread_handles = malloc(4*sizeof(pthread_t));

    loop(thread, 4){
        results[thread] = malloc(n * sizeof(int));
        pthread_create(&thread_handles[thread], NULL, math, (void *)thread);
    }

    printf("Hello from the main thread\n");

    loop(thread, 4);
        pthread_join(thread_handles[thread], NULL);

    loop(thread, 4){
        printf("Results of operation %d:\n", thread); 
        loop(i, n)
            printf("%d ", results[thread][i]);
        printf("\n");
       free(results[thread]);
    }

    free(thread_handles);
    free(a);
    free(b);
    free(results);

   return 0;    
}

void* math(void* op1){
    int op = (int) op1, i;

    printf("%d ", op);
    if (op == 0)
        loop(i, n)
             results[op][i] = a[i] + b[i];
    else if (op == 1)
         loop(i, n)
             results[op][i] = a[i] - b[i];
    else if (op == 2)
         loop(i, n)
             results[op][i] = a[i] * b[i];
    else
        loop(i, n)
            results[op][i] = a[i] / b[i];



    return NULL;
}

【问题讨论】:

  • 如果用户未能向程序提供参数,该程序应该 SEGFAULT。您应该在索引到 argv 之前检查 argc。
  • 我还建议你看一下这个answer 关于强制转换为 (void *) 的内容。我提到这个不是因为它与您的问题有关,而是如果您在不同的环境中编译可能会发现一些东西。
  • 如此意义非凡的变量名,如 'a' 和 'b' sigh 。这个宏:loop(i, n) 毫无用处,使代码混乱,更难理解。强烈建议用实际的“for()”语句替换这些宏调用。
  • 在调用 malloc() 或 calloc() 或 realloc() 函数时,始终检查 (!=NULL) 返回值,然后再使用该值,以确保操作成功
  • 编写math() 函数的更好方法是使用switch() 语句,当运算符不是4 个有效值之一时,该语句可以有default: 情况

标签: c ubuntu pthreads


【解决方案1】:

这个问题是由你学到的可怕的循环定义引起的。请忘掉它!

#define loop(i, n) for (i = 0; i < n; i++)

这就是问题所在:

loop(thread, 4);
//             ^ BAD! Putting a semicolon here makes the loop empty.

使用您选择的糟糕定义的正确版本是:

loop(thread, 4)

更好的方法是直接说出你的意思!

for(i=0; i<n; ++i)
{
   // Do Stuff
}

问题导致 pthread_join 只被调用一次,然后主线程继续运行。这可能发生在所有线程完成并在结果变量中提供它们的输出之前。不好!

【讨论】:

  • 这个问题不是由loop 宏引起的(尽管我同意,使用这样的宏对于可读性可能弊大于利)。问题只是loop(thread, 4); 中多余的分号。 OP 在正常 for 循环体之前使用分号也会遇到同样的问题:for (i=0; i&lt;n; i++);
  • @DaoWen 我同意你的评价。我很小心地说由宏引起,而不是宏是根本原因。
  • “宏是废话”我会没问题的
  • "问题导致 pthread_join 仅被调用一次" 并且此调用越界访问thread_handles(使用索引 5)并由此调用未定义的行为任何事情都可能发生......
  • 这解决了我的问题。我再也不会使用宏了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多