带有Pthreads的Hello World损坏内存

时间:2012-08-09 20:31:44

标签: c++ c pthreads segmentation-fault

我正在研究llnl.computing.gov pthreads教程中的一些简单的pthread示例。网站上的程序打印出threadid的地址,但是我想将id的地址传递给PrintHello,然后使用取消引用地址来获取id。我认为在那里睡眠每个线程应该打印8(线程数)。代码是

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NUM_THREADS  8

void *PrintHello(void *threadid)
{
   long *taskid = (long *)threadid;
   sleep(1);
   printf("Hello from thread %ld\n", *taskid);
   pthread_exit(NULL);
} 

int main(int argc, char *argv[])
{
  pthread_t threads[NUM_THREADS];
  int rc;
  long t;

  for(t=0;t<NUM_THREADS;t++) {
    printf("Creating thread %ld\n", t);
    rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &t);
    if (rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
    }
 }
 pthread_exit(NULL);
}

当我在Cygwin中编译并运行它时,它会出现堆栈损坏错误。如果我将PrintHello重写为:

void *PrintHello(void *threadid)
{
  long taskid = (long) threadid;
  sleep(1);
  printf("Hello from thread %ld\n", taskid);
  pthread_exit(NULL);
 }

它不会出错,它只是打印地址,我想取消引用地址并从main获取t的值。

有没有人对如何实现这一目标有一些指示?我知道我可以将t传递给pthread_create而不是&t,但我想这样做是出于学习目的。

3 个答案:

答案 0 :(得分:9)

当您从主线程调用pthread_exit(NULL)时,它会终止该线程。此时,main函数中的任何局部变量(包括t)都将被销毁,无法再使用。

如果主线程在使用t完成所有工作线程之前退出(通过pthread_create传递给它们的指针),则程序会显示未定义的行为。

程序包含竞争条件,因为来自工作线程的变量t的访问以及来自主线程的变量t的破坏是不同步的。解决此问题的一种方法是让主线程在退出之前与每个工作线程(通过pthread_join)连接。

答案 1 :(得分:4)

1)你传递了t地址,所以每个线程都会得到一个指向同一个变量的指针,这不是线程ID,它是一个long,它有一个不断变化的价值。您正在修改main中的变量并在每个其他线程中读取它,这是一个数据竞争。

2)可能会发生的事情是,当新线程执行main中的循环时,该变量已超出范围。当main退出时,它的局部变量将从堆栈弹出,所以当其他线程访问t时,它不再在堆栈上。您的程序中没有任何同步来防止这种情况,因此您在那里有另一个数据竞争。您需要在main等待线程完成,您可以通过调用pthread_join等待每个线程来完成,但这仍然不会改变其他线程尝试读取的事实变量,而它被另一个线程写入。

3)没有必要在那里调用pthread_exit,从函数返回或从main自动退出线程(就像调用exit(0)导致main()完成一样)

答案 2 :(得分:0)

一些指示?好吧,你的线程函数中有很多它们......

问题:你不能安全地传递你的局部变量的地址 - 它在主要退出时超出范围。您需要将指针声明为静态全局变量,或者将malloc()sizeof(long)字节的内存声明并使用它。