【问题标题】:Strange multi-threading output for different Platforms不同平台的奇怪多线程输出
【发布时间】:2016-04-12 14:41:06
【问题描述】:

我使用 gcc 编译器在 Ubuntu 14.04 和 CentOS 7 上执行了以下代码,但奇怪的是它对相同的输入显示不同的输出。有两个问题我无法解决。

  1. 对于第一次乘法 (1*1),总和(在主函数中)总是得到 0。
  2. Ubuntu 的输出完全出乎意料。 这是代码和两个输出。

代码

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#define N 15
struct matrix
{
    int num1, num2;
};
void* multiply(void *c);
int main()
{
    int i, j, rows, cols, a[N][N], b[N][N], sum, k, final, res[N][N],*ptr;
    pthread_t t1, t2;
    struct matrix m1;
    ptr=&sum;
    printf("Enter the number of rows: ");
    scanf("%d", &rows);
    printf("Enter the number of cols: ");
    scanf("%d", &cols);
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < cols; j++)
        {
            printf("Enter the value at: a[%d][%d] : ", i, j);           
            scanf("%d", &a[i][j]);
        }
    }
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < cols; j++)
        {
            printf("Enter the value at: b[%d][%d] : ", i, j);           
            scanf("%d", &b[i][j]);
        }
    }
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < cols; j++)
        {
            final = 0;
            for(k = 0; k < rows; k++)
            {
                m1.num1 = a[i][k];
                m1.num2 = b[k][j];
                pthread_create(&t1, NULL, (void*)multiply,(void*)&m1);
                pthread_join(t1, (void**)&ptr);
                sum=*ptr;
                printf("\t%d",sum);
                final += sum;
                res[i][j] = final;
            }
            printf("\n");
        }
    }   
    printf("The result is :\n");
    for(i = 0; i < rows; i++)
    {
        for(j = 0; j < cols; j++)
        {
            printf("%d\t", res[i][j]);
        }
        printf("\n");
    }
    return 0;
}
void* multiply(void *c)
{   
    struct matrix *m;
    m = (struct matrix *)c;
    int p = 0;
    p = m->num1 * m->num2;
    printf("\t%d * %d = %d",m->num1,m->num2,p);
    pthread_exit((void*)&p);
}

在 Ubuntu 上执行的输出

Enter the number of rows: 2
Enter the number of cols: 2
Enter the value at: a[0][0] : 1
Enter the value at: a[0][1] : 2
Enter the value at: a[1][0] : 3
Enter the value at: a[1][1] : 4
Enter the value at: b[0][0] : 1
Enter the value at: b[0][1] : 2
Enter the value at: b[1][0] : 3
Enter the value at: b[1][1] : 4
    1 * 1 = 1   0   2 * 3 = 6   32648
    1 * 2 = 2   32648   2 * 4 = 8   32648
    3 * 1 = 3   32648   4 * 3 = 12  32648
    3 * 2 = 6   32648   4 * 4 = 16  32648
The result is :
32648   65296   
65296   65296   

在 CentOS 上执行的输出

Enter the number of rows: 2
Enter the number of cols: 2
Enter the value at: a[0][0] : 1
Enter the value at: a[0][1] : 2
Enter the value at: a[1][0] : 3
Enter the value at: a[1][1] : 4
Enter the value at: b[0][0] : 1
Enter the value at: b[0][1] : 2
Enter the value at: b[1][0] : 3
Enter the value at: b[1][1] : 4
    1 * 1 = 1   0   2 * 3 = 6   6
    1 * 2 = 2   2   2 * 4 = 8   8
    3 * 1 = 3   2   4 * 3 = 12  4
    3 * 2 = 6   3   4 * 4 = 16  16
The result is :
6   10  
15  22  

【问题讨论】:

    标签: multithreading ubuntu gcc centos pthreads


    【解决方案1】:

    multiply 函数返回一个指向局部变量 p 的指针,函数结束后局部变量的生命周期结束。

    这里最简单的解决方案是不使用返回值,而是在传递给multiply()struct matrix 中为结果保留一个位置,因为该结构是在main 中分配的。更改struct multiply的定义:

    struct matrix
    {
        int num1, num2;
        int product;
    };
    

    更改multiply() 将结果放在这里:

    void *multiply(void *c)
    {   
        struct matrix *m = c;
    
        m->product = m->num1 * m->num2;
        printf("\t%d * %d = %d", m->num1, m->num2, m->product);
        return NULL;
    }
    

    更改main() 以从那里检索结果:

    pthread_create(&t1, NULL, multiply, &m1);
    pthread_join(t1, NULL);
    sum = m1.product;
    

    (旁注:变量sum 有一个令人困惑的名称,因为它不包含总和!)

    【讨论】:

    • 但是 pthread_join 的手册页说它将 pthread_exit() 返回的值设置为 ptr(我的程序中的 ptr) 指向的整数。考虑到这一点,如果我在开始时声明 ptr=&sum,我不应该只收到 p 的值吗?我试过这样做,但没有奏效。 here 是该手册页的链接。
    • 线程返回的退出状态不是指向的整数指针:它是指针本身(指向multiply() 中变量p 的指针)。该指针值被pthread_join() 愉快地返回到ptr,但它不再有效,因为指向的变量p 不再存在。 (手册页中提到的“目标线程提供给pthread_exit()的值”是一个指针值)。
    • 此外,ptr 会被pthread_join() 覆盖,因此您一开始将其设置为什么并不重要。它最终指向p,但p 不再存在。
    • 那么 CentOS 是如何显示相同代码的正确输出的呢?它仍然没有解释不同操作系统的不同输出。我在 Fedora 上试了一下,它运行良好,就像 CentOS 一样。
    • 它会在不同的环境中发生变化,因为这是您的代码存在的错误的本质——它的出现方式取决于如何以及何时重用该内存。 CentOS 和 Ubuntu 使用不同版本的 C 编译器和标准库。如果你仔细看,你会发现它在 CentOS 上也有问题 - 你的 CentOS 示例输出有 1 * 1 = 1 03 * 2 = 6 3 以及其他不正确的示例。
    猜你喜欢
    • 1970-01-01
    • 2020-12-29
    • 2014-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    相关资源
    最近更新 更多