c - pthreads并行化错误结果

标签 c multithreading pthreads pthread-join

我正在使用pthreads编写C程序。
目的是通过将给定数字的倍数作为参数传递来计算它们。
要相乘的数字和倍数的数量可以自由选择。
该程序用gcc -lpthread -Wall -Wextra in.c编译,可执行文件用./a.out num amount num amount ...调用
该程序为每个“输入对”分配内存,并为每次计算创建一个线程,
然后将所有线程连接起来,并将写入线程的内存区域打印到屏幕上。
问题是程序经常使至少一个输出留空(0x00)。
通过重复相同的输入,很少会出现正确的结果。
例如,输入./a.out 10 3 7 5 3 4的输出(此处已压缩)如下所示:

Thread 0 result: 10 20 30  or Thread 0 result: 0 0 0    but rarely the Thread 0 result: 10 10 0 
Thread 1 result: 0 0 0 0 0 or Thread 1 result: 0 0 0 0 0   expected    Thread 1 result: 7 14 21 28 35
Thread 2 result: 3 6 9 12  or Thread 2 result: 3 6 9 12     result:    Thread 2 result: 3 6 9 12
因此,我找到了两种解决方法,但是它们都不能解决问题。它们包含在代码中,但已被注释掉。
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define MAX_THREADS 100
int *thr_out[MAX_THREADS]; // global output record
// function to thread
void *threaded_mul(void* arguments[3])
{
  int* out = arguments[0];
  long num = (long)arguments[1];
  long len = (long)arguments[2];
  for(int i=0; i<len; i++)
    out[i]=num*(i+1);
  pthread_exit(NULL);
}

int main(int argc, char* argv[])
{
  int amt_thr = argc/2;       // one thread needs two arguments
  int thr_i_num[amt_thr];     // number to generate multiples
  int thr_o_len[amt_thr];     // how many multiples to generate
  pthread_t thr_id[amt_thr];  // holds thread ids
  long int thr_args[3];       // forms argument for pthread_create call
  printf("%d threads needed\n",amt_thr);
  for(int i=0; i<amt_thr;i++)
  { // calculate how much memory is needed for each thread
    int oi = 2*i+1; // 0 1 2 3 -> 1 3 5 7
    thr_o_len[i] = strtol(argv[oi+1], NULL, 10);
    thr_i_num[i] = strtol(argv[oi], NULL, 10);
    // allocate the memory
    thr_out[i]=calloc(thr_o_len[i], sizeof(int));
  }
  for(int i=0; i<amt_thr; i++)
  { // create threads
    thr_args[0] = (long)thr_out[i]; // address to write output to
    thr_args[1] = thr_i_num[i];     // input 'val' for thread (number to multiply)
    thr_args[2] = thr_o_len[i];     // output length 'len' for thread
    pthread_create(&thr_id[i], NULL, (void*)threaded_mul, &thr_args);
    //for(int i=0; i<32768; i++){}  //  either delay here
    //pthread_join(thr_id[i],NULL); // or wait until the thread finishes
  }
  printf("joining threads\n");
  for(int i=0; i<amt_thr; i++)
    pthread_join(thr_id[i],NULL);

   for(int t=0; t<amt_thr; t++)
  { // printing resuls
    printf("Thread %d result: ",t);
    for(int j=0; j<thr_o_len[t]; j++)
      printf("%d ",thr_out[t][j]);
    putchar('\n');
  }
  for(int i=0; i<amt_thr; i++)
    free(thr_out[i]);
  return 0;
}

我假设在创建线程之后,main继续正常运行,并且该线程立即(在另一个内核上)启动,但是地址空间相同。
我的观察是,在大多数情况下,至少有一个线程无法获取正确的参数,并且两个或多个线程执行相同的计算并写入相同的目的地,
因此,其他输出目的地保持不变。
如何避免这种行为?
编辑:根据您的回答,据我了解,问题是在新创建的线程从内存中读取其参数&thr_args之前,for循环//create threads已经在thr_args[]中写入了新参数。但是参数必须是pthread_create要求的指向内存的指针。
Edit2:我通过将所有线程的所有输入(每个线程3个)写入内存而不是由于上面段落中所述的原因而在thr_args[] -loop中更新全局输入变量for来解决了这个问题。

最佳答案

您可能应该发布预期的输出,但是从轻描淡写您的故事看来,您似乎不应在输出中找到零。
启动线程时,您传入了数组引用(thr_args [])。这意味着每个线程都会看到相同的参数,这是一个内存位置。您在线程创建循环中覆盖了此数组,因此任何特定线程所看到的都是与时间/os/#cores相关的。不太随机,但是该死的接近。
作为一个快速的技巧,我将围绕pthread_create的程序更改为:

 void *x = memdup(thr_args, sizeof thr_args);
 pthread_create(&thr_id[i], NULL, threaded_mul, x);
并在上面添加了一些功能:
static void *memdup(void *p, size_t n) {
        void *x;
        if ((x = malloc(n))) {
                memcpy(x, p, n);
                return x;
        } else {
                abort();
        }
}
和您的程序打印:
Thread 0 result: 10 20 30 
Thread 1 result: 7 14 21 28 35 
Thread 2 result: 3 6 9 12 
当然,这会泄漏。因此,您需要更正程序以将参数数组与线程相关联,并在该线程的连接成功后将其删除。

关于c - pthreads并行化错误结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66512055/

相关文章:

c - 如何在特定位置写入文件?

c - 在 C 中移动多维数组指针 - 不兼容的类型

c pthread传递int类型的数组

gdb - 让 gdb 在 'apply all' 操作上显示线程名称

c - 如何用 C 语言编写一个程序来计算作为参数的数字数量?

c - 从字符串读取大小后分配大小为 'n' 的缓冲区

java - 嵌套锁上的非法状态异常

c - 下面的C代码会生成多少个进程和线程?

c# - 我可以将鼠标事件处理程序放在单独的线程上吗?

C linux pthread需要 sleep 才能工作