【问题标题】:Trying to understand pointers and threads试图理解指针和线程
【发布时间】:2019-12-11 16:09:47
【问题描述】:

我对 C 语言相当陌生,并试图理解线程和指针。据我所知,这一行创建了一个线程

rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t); 

第四个参数是指针函数(void *)t的参数,这是一个指向变量t地址的指针,它是long类型?而指针函数将void指针的参数指向一个变量,即(void *)t

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 20

void *PrintHello(void *threadid)
{
   long tid;
   tid = (long)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   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("In main: 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);
       }
     }

   /* Last thing that main() should do */
   pthread_exit(NULL);
}

之后,我把指针函数和pthread_create改成了这样:

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

 rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &t);

那么现在void指针仍然指向变量t的地址?

*(long *)threadid 正在取消引用变量t? 并在所有线程中输出t的最终值。

我不确定我是否理解正确,如果我在某个地方误解了,我很感激任何建议。我的问题是(void *)t(void *) &amp;t,它们都是指向变量t的地址的指针,而我读取的指针只能指向地址而不是值,那么为什么(void *)t输出递增t 的值? taskid = *(long *)threadid; 如果我只做taskid = threadid 它会打印出t 的地址,那么*(long *) 会做什么?括号外的* 是取消引用吗?

【问题讨论】:

    标签: c multithreading pointers


    【解决方案1】:

    在某事之前将一个类型放在方括号中,就是将该值转换为该数据类型。因此,在您的示例中,(void *) tt 的值从long 转换为void *。这样做是因为 pthread_create 需要一个指针。

    &amp; 放在某物前面可以获得它的地址。所以&amp;t 得到t 的地址。然后如上所述将其转换为void *,尽管它并不是真正需要的,因为如果需要,任何指针都会自动转换为void *

    因此,在您的代码的第一个版本中,您将t 的实际值传递到您的线程中,方法是对其进行强制转换,使其看起来像一个指针,然后在线程内再次将其强制转换以获取@ 987654332@值。

    第二个版本是传入一个指向t的指针,所以每个线程在到达这一行时都会打印出t的值:

    taskid = *(long *)threadid;
    

    【讨论】:

    • taskid = *(long *)threadid;所以在这条线上我将它转换回long,但由于它是一个指向t的指针,我必须在括号外使用*来获取值,并转换(long *),因为它是一个指针?否则如果我只转换 (long) 它将不起作用,因为 t 是一个指针?
    • 不完全。您将其转换为long *,然后取消引用。您不能取消引用 void * 指针。
    • 知道了,非常感谢你的解释,我现在明白了:)
    【解决方案2】:

    要获取变量的地址,您必须使用&amp;

    (void*)t 没有得到t 的地址。它采用t 的值,并将该值视为void* 值。所以你有一个指向内存地址 0, 1, 2, ... 最多 NUM_THREADS-1 的指针。

    您不能使用这些指针,因为它们不指向有效地址。但是您可以使用(long)threadid 再次将它们视为数字。

    您需要创建void* 类型的唯一原因是因为pthreads 将其用作线程函数的参数。如果你使用了void *PrintHello(long threadid),那么在调用pthread_create 时会报错,表示函数类型错误。

    【讨论】:

    • 所以在第二个例子中,我必须强制转换 (long *)threadid,因为我传递了指向 t 的指针,也就是 t 的地址?
    • @aalang 是的。我希望你也明白为什么它会在所有线程中打印最终值。
    • 我有点明白为什么,但是否因为我调用了 sleep(1),并且当它完成睡眠时,t 值已经是最终值,所以它才开始分配 taskid线程ID?
    • 是的,就是这个原因。 (我不确定“它只开始将taskid分配给threadid”是什么意思,但你所说的其余部分是正确的)
    • 我的意思是在它休眠之后,然后只执行taskid = threadid的其余代码,到那时已经是最终值了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2020-10-03
    相关资源
    最近更新 更多