4

我正在研究一些来自 llnl.computing.gov pthreads 教程的简单 pthread 示例。网站上的程序打印出threadid的地址,但是我想把id的地址传给PrintHello,然后用dereference这个地址来获取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 的值。

有人对如何实现该目标有一些指示吗?我知道我可以传递tpthread_create而不是,&t但我想这样做是为了学习目的。

4

3 回答 3

9

当您pthread_exit(NULL)从主线程调用时,它会终止该线程。此时,main函数中的任何局部变量,包括t,都被破坏并且不能再使用。

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

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

于 2012-08-09T20:36:32.103 回答
4

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

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

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

于 2012-08-09T20:37:10.507 回答
0

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

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

于 2012-08-09T20:39:06.653 回答