【问题标题】:Pthreads and Structures C++Pthreads 和结构 C++
【发布时间】:2016-05-26 03:34:34
【问题描述】:

我在 C++ 中使用结构,我尝试在该结构中保存指针,但是当我尝试在线程中使用该结构时,我无法获取该结构的数据。

struct threadData {
   void* memPointer;
   void* instructionPointer;
   void* stackPointer;
   int memsize;
};

void *worker_thread(void *arg) {
    struct threadData *my_data;
    my_data = (struct threadData *) arg;
    cout<<"INSTRUCTION POINTER: "<<my_data->instructionPointer<<endl;
    cout<<"MEMORY POINTER: "<<my_data->memPointer<<endl;
    cout<<"STACK POINTER: "<<my_data->stackPointer<<endl;
    cout<<"MEMORY SIZE: "<<my_data->memsize<<endl;

 }

 int main() {
    pthread_t my_thread;
    int ret;
    struct threadData td = { calloc(1, 32), calloc(1000000, 64),     calloc(34, 4),6475 };
    ret = pthread_create(&my_thread, NULL, worker_thread, (void *) &td);
    pthread_detach(my_thread);
    //pthread_exit(NULL);
 }

但是当我在 pthread_detach 之后使用 pthread_exit(NULL) 时,我可以使用方法“worker_thread”中的结构信息。

【问题讨论】:

  • 如果您使用 C++,为什么不使用构造函数来初始化您的结构?您还使用了 C 风格的强制转换,并使用 struct 关键字来引用您的结构类型(这在 C++ 中几乎从不需要)。这是非常类似于 C 的 C++ 代码...
  • C++11 实现你正在尝试做的事情:coliru.stacked-crooked.com/a/f0b3dadb23bd7bba
  • @kfsone 您可能还需要将 calloc 调用替换为 new char[x*y] 以使其完全类似于 C++。为了完整起见,我将释放/删除分配的数据。当然,这里没有必要,但因此提前考虑从一开始就销毁任何分配的内存可能会阻止您在将来的某个时间创建内存泄漏......
  • 除了 Aconcagua 的建议之外,我将移动 inside 字段的 new 调用,构造函数只会将大小作为参数。 void* 类型也让我感到厌烦......在精心设计的 C++ 代码中,几乎总是有更好的替代 void* 的方法。

标签: c++ multithreading pointers structure


【解决方案1】:

由于td 是在main 的堆栈上分配的,它会被运行时从main 返回后执行的一些清理代码破坏。将 td 结构分配到堆上而不是堆栈上,它将按预期工作:

struct threadData tdVal = { calloc(1, 32), calloc(1000000, 64),     calloc(34, 4),6475 };
struct threadData *td = malloc(sizeof(*td));
*td = tdVal;
// ...
ret = pthread_create(&my_thread, NULL, worker_thread, (void *) td);

但是,您仍然有问题。 Returning from main will kill the other pthreads in your program。由于您的代码中没有同步阻止 main 在运行 worker_thread 之前完成,因此您甚至无法保证 worker_thread 将运行。

您应该分离工作线程,而是使用pthread_join 确保它在从main 返回之前已完成。另请注意,如果您确保mainworker_thread 完成之前没有返回,那么将td 留在堆栈上没有问题。

【讨论】:

  • 如果使用 pthread_join,那么在堆栈上放置 td 没有问题。
  • @Aconcagua - 是的,谢谢。我已经更新了答案以明确这一点。
【解决方案2】:

没有pthread_exit,你从main返回,局部变量td在其他线程完成之前就被销毁了。

通过调用pthread_exit,您强制主线程等待其他线程完成,因此td 不会被过早销毁。

正如@Aconcagua 所注意到的,pthread_exit 的文档说调用线程已终止。它不会对主线程产生异常,因此至少在原则上,当其他线程仍在执行时,主线程的堆栈可能会消失。这意味着即使调用pthread_exit,您也有未定义的行为。

【讨论】:

  • 来自pthread_exit man pages:“retval 指向的值不应位于调用线程的堆栈上,因为该堆栈的内容在线程终止后未定义。”如果这也适用于主线程,则同样适用于 td - 在另一个线程中访问 td 时会导致未定义的行为。
  • @Aconcagua:我不确定您要表达什么观点,因为在这种情况下,retval(pthread_exit 的参数)将为 NULL。
  • 重要的一点不是 retval,而是堆栈未定义 - 在我们的例子中是 td。因此,如果从另一个线程访问td,这是未定义的行为(除非从主线程调用 pthread_exit 的行为不同 - 不过我提供的链接中没有提示)。
  • @Aconcagua。好的我知道了。我在想主线程上的堆栈将被保留,直到所有其他线程完成,但看起来不能保证。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多