多个线程查找整数的主因子,分段错误

时间:2019-07-13 02:00:36

标签: c multithreading pthreads

我无法弄清楚我的指针在做什么。导致分段错误。我确信问题出在我使用的指针数组和我正在使用的pthread_join上。

目标是将多个整数读入gcc编译器,然后打印出具有所有因子的整数,例如12:2 2 3

我创建了一个结构,该结构包含一个int数组以存储每个整数的因数(当factor函数将其拉开时)和一个counter(numfact)来存储数组中存储了多少个因数。

我在底部注释掉了打印出因素的部分。

我认为问题是我如何尝试将pthread_join的输出存储在指针数组ptr []中。每当我注释掉它时,都不会出现细分错误。 要么我以我不理解的方式弄乱了指针,要么无法使用指针数组。无论哪种方式,几个小时后,我都会被卡住。

请帮助。

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

struct intfact
{
    long int factors[100];
    int numfact;
};


struct intfact *factor(long int y) 
{ 
    struct intfact threadfact;
    threadfact.numfact = 0;

        // Store in struct the number of 2s that divide y 
        while (y % 2 == 0) 
        { 
        threadfact.factors[threadfact.numfact] = 2;
        threadfact.numfact++;
            y = y/2; 
        } 

        // Store in struct the odds that divide y
        for (int i = 3; i <= floor(sqrt(y)); i = i+2) 
        { 
            while (y % i == 0) 
            { 
            threadfact.factors[threadfact.numfact] = i;
            threadfact.numfact++;
                y = y/i; 
            } 
        } 

        // Store in struct the primes > 2
        if (y > 2) 
    {
        threadfact.factors[threadfact.numfact] = y;
        threadfact.numfact++;
    }
    struct intfact *rtnthred = &threadfact;
    return rtnthred;
} 


/* Trial Division Function */
void *divde(void *n)
{
    long int *num = (long int *) n;
    struct intfact *temp = factor(*num);
    return temp;
}


/* Main Function */
int main(int argc, char *argv[])
{
    pthread_t threads[argc-1];
    void *ptr[argc-1];

    /* loop to create all threads */
    for(int i=0; i < argc; i++)
    {
        long temp = atol(argv[i+1]);
        pthread_create(&threads[i], NULL, divde, (void *) temp);
    }

    /* loop to join all threads */
    for(int i=0; i < argc; i++)
    {
        pthread_join(threads[i],(void *) ptr[i]); //THIS POINTER IS THE PROBLEM
    }


    /* loops to print results of each thread using pointer array*/
    //for(int i = 0; i < argc; i++)
    //{
    //  printf("%s: ", argv[i+1]); /* print out initial integer */
    //  struct intfact *temp = (struct intfact *) ptr[i]; //cast void pointer ptr as struct intfact pointer
    //  printf("%d", temp->numfact);
        //for(int j = 0; j < temp->numfact; j++) /*(pull the numfact(count of factors) from the struct intfact pointer??)*/
        //{
        //  printf("%d ", temp->factors[j]); /* print out each factor from thread struct */
        //}
    }

}

在我的Linux)终端中,此代码存储在p3.c中

“ ./ p3 12”应为“ 12:2 2 3”

1 个答案:

答案 0 :(得分:1)

对于初学者:

这里

    long temp = atol(argv[i+1]);
    pthread_create(&threads[i], NULL, divde, (void *) temp);

您定义一个long int并将其作为参数传递给线程。例如12

然后在线程函数中

void *divde(void *n)
{
  long int *num = (long int *) n;

您将传入的long int视为指向long int的指针。

然后在这里取消引用

    ... = factor(*num);

因此,这个*num例如将变成*12。那就是引用内存地址12读出其内容并将其传递给factor)。除了这很可能是无效地址这一事实之外,没有任何相关存储,至少没有您的代码定义。

要(或多或少地修复)此操作

void *divde(void *n)
{
  long int num = (long int) n;
 ... = factor(num);

评论中提到了第二个问题:Multiple threads to find prime factors of integers, segmentation fault


您要解决的问题是并行编程的一种特殊情况,即并行运行的任务是完全独立的。在这种情况下,赋予每个任务自己的上下文是有意义的。这里的上下文将包括

  • 线程ID,
  • 特定于线程的输入
  • 及其特定输出。

在C语言中,可以使用结构对变量进行分组,因为您的实现已经针对任务的输出提出了

struct intfact
{
  long int factors[100];
  int numfact;
};

因此缺少的是线程ID和输入。只需添加这样的示例。

/* group input and output: */
struct inout
{
  long int input;
  struct intfact output;
};

/* group input/output with thread-id */
struct context
{
  pthread_t thread_id;
  struct inout io;
};

现在在启动线程之前定义所需的上下文:

int main(int argc, char *argv[])
{
  size_t num_to_process = argv - 1;
  struct context ctx[num_to_process];

然后创建传递所需内容的线程,将其与输出的空间/内存一起输入:

  for (size_t i = 0; i < num_to_process ; i++)
  {
    ctx[i].io.input = atol(argv[i]);
    pthread_create(&ctx[i].thread_id, NULL, divide, &ctx[i].io);
  }

在线程函数内部,将收到的void指针转换回其实型:

void *divide(void * pv)
{
  struct inout * pio = pv; /* No cast needed in C. */

定义处理函数以获取指向上下文特定的输入/输出变量的指针:

void factor(struct inout * pio) /* No need to return any thing */
{ 
  /* Initialise the output: */
  pio->output.numfact = 0;

  /* set local copy of input: */
  long int y = pio->input; /* One could also just use pio->input directly. */

threadfact替换所有其他pio->output的出现。

使用

  return;
}

离开处理功能。

然后在线程函数内部调用处理函数:

  factor(pio);

使用

  return NULL;
}

离开线程功能。

main()中加入而不会从线程中得到任何结果:

  /* loop to join all threads */
  for (size_t i = 0; i < num_to_process; i++)
  {
    pthread_join(ctx[i].thread_id, NULL);
  }

将所有内容放在一起:

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

struct intfact
{
  long int factors[100];
  size_t numfact;
};

/* group input and output: */
struct inout
{
  long int input;
  struct intfact output;
};

/* group input/output with thread-id */
struct context
{
  pthread_t thread_id;
  struct inout io;
};

void factor(struct inout * pio)
{
  /* Initialise the output: */
  pio->output.numfact = 0;
  /* set local copy of input: */
  long int y = pio->input; /* One could also just use pinout->input directly. */

  if (0 == y)
  {
    return; /* Nothing to do! */
  }

  // Store in struct the number of 2s that divide y
  while (y % 2 == 0)
  {
    pio->output.factors[pio->output.numfact] = 2;
    pio->output.numfact++;
    y = y/2;
  }

  // Store in struct the odds that divide y
  for (int i = 3; i <= floor(sqrt(y)); i = i+2)
  {
    while (y % i == 0)
    {
      pio->output.factors[pio->output.numfact] = i;
      pio->output.numfact++;
      y = y/i;
    }
  }

  // Store in struct the primes > 2
  if (y > 2)
  {
    pio->output.factors[pio->output.numfact] = y;
    pio->output.numfact++;
  }

  return;
}

void *divide(void * pv)
{
  struct inout * pio = pv; /* No cast needed in C. */

  factor(pio);

  return NULL;
}

int main(int argc, char *argv[])
{
  size_t num_to_process = argc - 1;
  struct context ctx[num_to_process];

  for (size_t i = 0; i < num_to_process; i++)
  {
    ctx[i].io.input = atol(argv[i+1]);
    if (!ctx[i].io.input)
    {
      fprintf(stderr, "COnversion to integer failed or 0 for '%s'\n", argv[i]);
    }
    pthread_create(&ctx[i].thread_id, NULL, divide, &ctx[i].io);
  }

  /* loop to join all threads */
  for (size_t i=0; i < num_to_process; i++)
  {
    pthread_join(ctx[i].thread_id, NULL);
  }

  /* loops to print results of each thread using pointer array*/
  for(size_t i = 0; i < num_to_process; i++)
  {
    printf("%ld: ", ctx[i].io.input); /* print out initial integer */
    printf("%zu factors --> ", ctx[i].io.output.numfact);

    for(size_t j = 0; j < ctx[i].io.output.numfact; j++)
    {
      printf("%ld ", ctx[i].io.output.factors[j]); /* print out each factor from thread struct */
    }

    putc('\n', stdout);
  }
}