Пытаться понять указатели и темы - PullRequest
2 голосов
/ 11 декабря 2019

Я довольно новичок в C и пытаюсь понять темы и указатели. Насколько я знаю, эта строка создает поток

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

Четвертый аргумент принимает аргумент для функции указателя (void *)t, и это указатель на адрес переменной t, которая являетсяlong тип? И функция указателя принимает аргумент пустого указателя на переменную, который равен (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 *) &t, они оба являются указателями на адрес переменной t, и я читаю указатели могут указывать только адреса, но не значения, так почему (void *)t выводит инкрементзначения t? taskid = *(long *)threadid; И если я просто наберу taskid = threadid, он печатает адрес t, что делает *(long *)? * вне скобок разыменовывается?

Ответы [ 2 ]

2 голосов
/ 11 декабря 2019

Помещение типа в скобки перед тем, как что-либо приведёт это значение к этому типу данных. Таким образом, в ваших примерах (void *) t преобразует значение t из long в void *. Это сделано потому, что pthread_create ожидает указатель.

Помещение & перед чем-либо дает адрес этого. Так &t получает адрес t. Затем он приводится к void *, как описано выше, хотя в действительности это не нужно, поскольку любой указатель будет автоматически приведен к void *, если требуется.

Так что в первой версии вашего кода выпередача фактического значения t в поток, приведение к нему, чтобы он выглядел как указатель, а затем приведение его обратно внутрь потока для получения значения long.

Вторая версияпередавая указатель на t in, таким образом, каждый поток выведет значение t в момент достижения этой строки:

taskid = *(long *)threadid;
2 голосов
/ 11 декабря 2019

Чтобы получить адрес переменной, вы должны использовать &.

(void*)t не получает адрес t. Он принимает значение t и обрабатывает это значение как значение void*. Таким образом, у вас есть указатель на адрес памяти 0, 1, 2, ... до NUM_THREADS-1.

Вы не можете использовать эти указатели, потому что они не указывают на действительные адреса. Но вы можете снова обращаться с ними как с числами, используя (long)threadid.

Единственная причина, по которой вам нужно сделать тип void*, заключается в том, что именно это pthreads использует в качестве параметра функции потока. Если вы используете void *PrintHello(long threadid), то при вызове pthread_create вы получите ошибку, из-за которой у функции будет неправильный тип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...