为什么pthread_join在上一次迭代中失败(给出分段错误)?

ban*_*ntz 0 c multithreading pthreads pthread-join

多线程初学者在这里。恰好在第5次迭代(即执行pthread_join(threadID [4],NULL)时),我的程序由于分段错误而失败。

我正在创建多个线程以从计数器变量中加减1以研究竞争条件。一切正常,直到我尝试5个线程或更多。恰好在pthread_join(threadID [4],NULL)的最后一次迭代中,它失败了,我无法确定原因。我确定问题出在哪里,因为我使用printf语句查看失败之前到达的位置。

#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <time.h>

int opt_threads;
int opt_iterations;
long nThreads;
long nIterations;
int opt_yield;
long long counter;

void add(long long *pointer, long long value) {
  long long sum = *pointer + value;
  if (opt_yield)
    sched_yield();
  *pointer = sum;
}

void *thread_worker(void * arg) {
  long i;
  for (i=0; i<nIterations; i++) {
    add(&counter, 1);
    add(&counter, -1);
  }

  return arg;
}

int main(int argc, char *argv[]) {
  int c;

  pthread_t *threadID = malloc(nThreads * sizeof(pthread_t));
  if (threadID == NULL) {
    fprintf(stderr, "Thread memory allocation failed\n");
    exit(1);
  }

  static struct option long_options[] =
    {
      {"threads", required_argument, 0, 't'},
      {"iterations", required_argument, 0, 'i'},
      {"yield", no_argument, 0, 'y'},
      {0,0,0,0}
    };

  while (1) {
    c = getopt_long(argc, argv, "", long_options, NULL);
    if (c==-1) break;

    switch(c) {
    case 't':
      opt_threads = 1;
      nThreads = atoi(optarg);
      break;
    case 'i':
      opt_iterations = 1;
      nIterations = atoi(optarg);
      break;

    case 'y':
      opt_yield = 1;
      break;

    default:
      fprintf(stderr, "Bad argument!\n");
      exit(1);
    }
   }

counter = 0;
struct timespec start, finish;
int i;

//start clock
clock_gettime(CLOCK_MONOTONIC, &start);

//create
for (i=0; i < nThreads; i++) {
  pthread_create(&threadID[i], NULL, &thread_worker, NULL);
  printf("Created thread[%ld]\n", i);
}

//wait (join)
  /*for (i=0; i < nThreads; i++) {
    printf("Now i is %ld\n", i);
    if (pthread_join(threadID[i], NULL) != 0)
      fprintf(stdout,"ERRRRROOOORRRRRRRR\n");

  }*/

  pthread_join(threadID[0], NULL);
  pthread_join(threadID[1], NULL);
  pthread_join(threadID[2], NULL);
  pthread_join(threadID[3], NULL);
  pthread_join(threadID[4], NULL);

  printf("about to end clock\n");
  //finish clock
  clock_gettime(CLOCK_MONOTONIC, &finish);

  printf("finished clock\n");

  long seconds = finish.tv_sec - start.tv_sec;
  long ns = finish.tv_nsec - start.tv_nsec;
  long runTime = (seconds + ns) * 1000000000L;
  long nOperations = nThreads * nIterations * 2;
  long avgOperations = runTime / nOperations;
  long run_time = 1000000000L * (finish.tv_sec - start.tv_sec) + finish.tv_nsec - start.tv_nsec;

  //Print
  if (opt_yield == 0)
    fprintf(stdout, "add-none, %ld, %ld, %lld, %ld, %lld, %lld\n", nThreads, nIterations, nOperations, run_time, run_time/nOperations, counter);

  else if (opt_yield == 1)
    fprintf(stdout, "add-yield-none, %ld, %ld, %lld, %ld, %lld, %lld\n",nThreads, nIterations, nOperations, run_time, run_time/nOperations, counter);

exit(0);
}
Run Code Online (Sandbox Code Playgroud)

我希望程序能够正确等待第5个线程,但是由于分段错误而失败。

Jon*_*ler 5

您的main功能开始:

int main(int argc, char *argv[])
{
    int c;

    pthread_t *threadID = malloc(nThreads * sizeof(pthread_t));
Run Code Online (Sandbox Code Playgroud)

由于nThreads是没有显式初始化程序的全局变量,因此它的值为零-您尚未分配可合法使用的任何内存。访问该内存将导致不确定的行为。

将内存分配推迟到知道需要多少线程之后。

未定义的行为意味着任何事情都可能发生,包括在不起作用之前一直起作用。

您还需要将线程连接代码重写为一个循环,以匹配创建线程的循环。