【问题标题】:Passing normal data to pthread void *将普通数据传递给 pthread void *
【发布时间】:2011-05-04 09:59:02
【问题描述】:

pthread 函数采用 void * 参数。如何发送一个普通的结构,而不是一个指针?

我想向一个 pthread 函数发送一个非指针结构。

另外我想发送一个指向 void * 函数的指针,这是怎么做的呢?可以将任何指针发送到 void * 函数吗?

【问题讨论】:

  • 要传递一个结构,你需要传递它的地址(将它转换成一个指针)。但是,您需要确保对象不会被破坏(因为线程将引用它)。是的,您可以将任何指针传递给 void *
  • 你不能(AFAIK)。指向基于堆的结构的指针有什么问题?
  • 我可以不只是将这样的结构 &thestruct 发送到 (void *)
  • @Helium3:是的,但是确保结构不会消失。因此,例如,如果它是一个局部变量,该函数可能会在一个线程中返回,而新线程仍然有一个指向不再存在的对象的指针......
  • @forsvarir:如果我有一个 GPSLocation 的结构。我有一个看门狗线程启动和监控 GPS I/O 线程和 GPS 导航线程。我需要将结构传递给看门狗,然后将其从看门狗传递给导航线程。当每个线程函数从 void * 回退时,是否会复制它?如果传入一个指针,这是否会消除坏数据或结构丢失的可能性/

标签: c pthreads


【解决方案1】:

不可能;你必须发送一个指针。但是,void * 可以指向任何东西。如果您的结构变量名为foo,您可以简单地将其作为(void *) &foo 传递,在函数内部,您可以将其转换回例如struct Foostruct Foo * fooPtr = (struct Foo *) param;struct Foo foo = *((struct Foo *) param);

编辑:正如评论中提到的@forsvarir,foo 不能是局部变量(除非调用函数等待线程完成)。请参阅@Gavin Lock 的帖子。

【讨论】:

    【解决方案2】:

    根据您的 cmets,您需要执行以下操作...

    在您的主代码中:

    void PassSomeStuff(struct TheStruct myStruct) {
        struct TheStruct *pStruct = malloc(sizeof(struct TheStruct));
        memcpy(pStruct, &myStruct, sizeof(struct TheStruct));
    
        /* Start the watchdog thread passing in the structure */
        pthread_create(/* other args */, &myWatchDogThreadFunc, pStruct); */
    }
    

    在你的看门狗线程中:

    void *myWatchDogThreadFunc(void *pArgs) {
        struct TheStruct *pStruct = (struct TheStruct *)pArgs;
    
        /* use the struct */
    
        /* Pass Ownership to the navigation thread*/
        /* Start the navigation thread passing in the structure */
        pthread_create(/* other args */, &myNavigationThreadFunc, pStruct); 
    }
    

    在您的导航线程中:

    void *myNavigationThreadFunc(void *pArgs) {
        struct TheStruct *pStruct = (struct TheStruct *)pArgs;
        /* use the struct */
    
        /* cleanup */
        free(pStruct);  /* or pass it to somebody else... */
    }
    

    你不能只做:

    void PassSomeStuff(struct TheStruct myStruct) {
        pthread_create(/* other args */, &myStruct);
    }
    

    因为myStruct 将被清理...当PassSomeStuff 返回时。获取地址(获取指向它的指针),不会复制对象。

    注意:

    • 只要您确定所有线程都已完成,您的任何线程都可以通过调用 free 来清理结构。
    • 所有线程(主线程、看门狗、导航)都引用结构的同一个实例(因此,如果它们正在更改其内容,您可能需要使用锁定来保护它)。如果这不是预期的效果,那么您需要在每个步骤中创建 (malloc) 结构的新副本,以便每个线程都有自己的值副本。

    【讨论】:

    • 我要从一开始就传递一个指针。在将其发送到看门狗(也是一个线程)之前对其进行 malloc,然后看门狗必须将其传递给 gps nav 线程。那么我可以将指针沿 void * pthread args 传递吗?
    • @Helium3:我已经更新了我的帖子以反映我认为你在说什么,包括底部的一些注释。简短的回答是肯定的(假设我理解正确)。
    【解决方案3】:

    如前所述,您必须传递一个指针。将 void* 视为无类型指针,因此您必须在线程函数中将其转换回正确的类型。 (见 Aasmund 的回答)

    正如 forsvarir 所提到的,您必须确保指向的结构在线程使用它之前没有被破坏 - 最安全的方法是在堆上新建结构并将其地址和所有权传递给线程函数.

    我所说的“传递所有权”的意思是通知结构的函数不得删除它,线程函数必须在完成后删除结构用它。

    【讨论】:

      【解决方案4】:

      这不是一个完整的答案,而是其他人提供的警告的替代解决方案,以确保在新线程获取结构时仍然存在该结构。当然你可以使用malloc来获取它,并让新线程负责freeing它。在许多方面,这似乎是最简单和最便宜的方式(不需要同步),但同步实际上隐藏在 mallocfree 中,并且可能有点贵,特别是因为大多数面向线程的分配器(ptmalloc 和 tcmalloc 用于例如)当释放内存的线程与分配它的线程不同时会产生额外的成本。

      您可以使用的另一种方法是在您的 init 结构中放置一个 pthread 屏障,然后等待它:

      pthread_barrier_init(&init_struct.barrier, 0, 2);
      pthread_create(&td, 0, start_func, &init_struct);
      pthread_barrier_wait(&init_struct.barrier);
      

      并让线程启动函数在将结构复制到自己的自动存储后也调用pthread_barrier_wait(arg->barrier);

      【讨论】:

        猜你喜欢
        • 2011-02-09
        • 1970-01-01
        • 2011-12-11
        • 1970-01-01
        • 2021-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多