【问题标题】:Passing a struct to pthread_create, undefined values after cast?转换后将结构传递给pthread_create,未定义的值?
【发布时间】:2012-08-20 12:00:26
【问题描述】:

我正在尝试将结构作为参数传递给 pthread_create,但似乎得到了一些奇怪的结果。

该结构有两个成员,第一个是 int,第二个是函数指针:

typedef struct
{
  int num;
  void (*func)(int);
} foo_t;

我试图在结构中使用的函数:

void myfunc(int mynum)
{
   printf("mynum: %d\n", mynum);
}

这是我将传递给我的线程的结构的声明:

foo_t f;
f.num = 42;
f.func = &myfunc;

对 pthread_create 的调用:

pthread_create(&mythread, NULL, mythreadfunc, &f);

最后,我的线程函数:

void mythreadfunc(void *foo)
{
   foo_t f = *(foo_t *)foo;
   printf("num: %d\n", f.num); // Prints: num: 32776 (undefined?)
   (*f.func)(f.num);  // Segfaults (again, undefined?)
...

似乎 mythreadfunc 中的强制转换似乎不起作用,我不知道为什么。有什么建议么?谢谢。

【问题讨论】:

  • 你能发布完整的代码吗?错误很可能出现在您没有向我们展示的代码中。 (如f在线程可以访问之前超出范围。)
  • @DavidSchwartz 正如你猜到的那样,这是一个范围问题,下次我会尝试发布一个更“独立”的示例,谢谢。

标签: c pointers struct pthreads


【解决方案1】:

Papergay 的回答绝对是一种解决方案,但如果您想避免动态分配,可以使用的另一种方法就是使用同步。我最喜欢的方法是在结构中放置一个初始值为零的信号量,让父级等待信号量,子级在完成从结构中读取值后发布信号量。

【讨论】:

  • 谢谢,这不会导致相同的范围问题(这将需要我将此特定结构声明为全局结构)?
  • 没有。调用者(pthread_create,在父线程中)在完成对信号量的等待之前无法返回,因此在此之前结构不会超出范围。
  • 啊,好吧。我正在使用pthread_tryjoin_np,它是pthread_join() 的非阻塞版本,所以我想要让它工作,我应该重新使用pthread_join()
  • 嗯?这与你的问题无关。
  • 如您所知,这并不是我的强项。我解释您的答案的方式是:将结构中的信号量“标志”初始化为 0,然后在新创建的线程中将其设置为 1,同时检查调用 pthread_create 的父线程中的信号量。是这么简单还是有更优雅的信号量处理方式? (谢谢!)
【解决方案2】:

您通过引用传递了您的foo_t f。如果您要从 pthread_create 调用函数或其他地方更改您的 f,例如离开相应的范围会从堆栈中删除/删除 f,那么您在线程中的引用(很可能)无效。至少你不应该再访问它了。

改为使用带有动态分配变量的指针。

虽然我无法证明您提供的代码会发生这种情况。

编辑:

指针用于存储对象/变量的地址。在C/C++ 中,您可以让它指向一个动态分配的内存段。为此查找malloc/new。您可以使用指针执行所谓的dereferencing 并访问对象/变量本身。

您可以传递每个值的指针,这意味着您不会传递对象/变量本身,而是传递 RAM 中对象/变量的地址(= 位置)。动态分配的变量/对象的内存管理是程序员的责任,所以当指针范围结束时你的对象不会被删除,只会删除存储地址的指针。

【讨论】:

  • 谢谢,您提到的似乎是范围问题。如果我将f 声明为全局变量,它似乎可以正常工作。不过,我无法弄清楚您答案的指针位-即使我在pthread_Create() 中传递了指向f 的指针,我不会有相同的范围问题吗?
  • 将其声明为全局是最糟糕的解决方案。 Papergay 没有说“传球”。您已经在传递一个指针,这是您可以传递的唯一可能的东西。 Papergay所说的是传递一个指向具有动态存储时长的对象(malloc获得的对象)的指针,而不是指向具有自动存储时长的对象的指针(局部变量)。
  • 我更新了我的帖子,让您对指针的使用有所了解。但是发教程实在是太多了。反正有很多在线教程和文档/书籍,所以我怀疑你会遇到问题......
  • 谢谢,所以基本上我应该 malloc() 堆中的一个区域,我的结构的大小,相应地设置值并将指针传递给 pthread_create 调用中的那个 - 这听起来对吗?
  • 好吧,我看不出你的回答有什么问题,所以请点赞。这是一个明显且常见的解决方案 - 新线程获取结构的所有权,并且可以对它做任何它想做的事情,使用它,释放它,将它的指针排队到另一个线程,保持它直到它在应用程序关闭时被释放,等等。有什么问题吗?
猜你喜欢
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-24
  • 2011-07-21
  • 2023-03-18
  • 2017-07-18
  • 2020-09-26
相关资源
最近更新 更多