2015-09-09 1 views
1

Я пытаюсь понять pthread, и у меня есть небольшой прогресс. Теперь я использую его без каких-либо проблем.Почему функция принимает указатель на пустоту?

Однако это требуется для создания методов резьбы следующим образом:

void *SomeMethod(void* x) 
{ 
    //Do Something 
} 

Почему необходимо создать функцию, которая принимает указатель void? Разве мы не можем использовать pthread с такой функцией?

void SomeMethod() 
{ 
} 
+2

Вы можете тривиально написать оболочку: 'void * ThreadMethod (void *) {SomeMethod(); return NULL; } ' –

+0

Фактически' void * foo() 'является допустимым C, хотя и устаревшим, так как он не указывает его список параметров. – Noldorin

ответ

5

Поскольку функция pthread_create принимает аргумент типа void* (*)(void*), который является функцией принятия void* и возвращения void*, так, чтобы создать поток, используя pthread_create это то, что вам нужно использовать.

API pthread_create API использует это, чтобы вы могли передавать данные в новый поток и получать данные обратно. Если вы не хотите ничего пропускать, вам все равно придется встречаться с этим интерфейсом, но просто передайте его NULL.

Просто потому, что вы не хотите передавать какие-либо аргументы в свою новую тему прямо сейчас, это не значит, что API должен быть разработан только для поддержки вашего текущего варианта использования. Гораздо лучше иметь API, написанный с точки зрения функции, принимающей void* (который необязательно может быть передан NULL), чем иметь API в терминах функции, не принимающей аргументов, и требующей от пользователей создания собственных решений для передачи данных в новый поток.

В C++ вы можете использовать любой тип функции для нового потока и передать любые аргументы, что вам нужно:

std::thread t(&SomeMethod); 
3

Потому что они хотели написать только одну функцию для создания потоков - взять и возврат данные.

В противном случае им придется писать как минимум четыре возможности.

Вы свободны, игнорируя входной параметр и возвращаемое значение.

Просто вопрос простоты

3

согласно man page из pthread_create(), мы можем видеть, подпись функции

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
       void *(*start_routine) (void *), void *arg); 

где третий аргумент типа

void *(*start_routine) (void *) 

, что означает, что он ожидает указатель на функцию с возвращаемым типом void * и принимает аргумент void *. Таким образом, нам необходимо определить функцию потока соответственно.

Тем не менее, в отношении использования void указателя для передачи аргументов, цитирование C11, глава §6.3.2.3

Указатель на void могут быть преобразованы в или из указателя на любой тип объекта. Указатель на любой тип объекта может быть преобразован в указатель на void и обратно; результат сравнивается с исходным указателем.

Как мы можем видеть, void указателя используется для передачи любого типа данных для функции потока, при условии, что преобразуется обратно к фактическому типу внутри функции.

Кроме того, FWIW, не пытайтесь отклоняться от необходимой подписи указателя функции, так как стандарт четко предписывает

[....] Если преобразованный указатель используется для вызова функции которого тип не совместим с ссылочным типом, поведение не определено. Если вы не хотите (нужно) передать какое-либо действительное значение аргумента, вы всегда можете пройти NULL.

3

Потому что нередко мы хотим дать потоку что-то работать (или с, или выключить, или что-то еще). Очень типичным примером является передача экземпляра класса, поэтому вы можете совершать вызовы функций-членов класса.

Но это могут быть всевозможные другие вещи - структура или указатель на некоторые простые данные.

Конечно, использование std::thread в любом случае скроет большинство таких вещей, и вам не нужно беспокоиться об этом. Я бы настоятельно рекомендовал использовать std::thread вместо pthread в целом.

2

void *SomeMethod(void* x) используется как точка входа для новой резьбы. Как вы должны действовать, если хотите передать в новый поток некоторые данные (структура, буфер, регулярное целое и т. Д.)? Специально для этого точка входа метод принимает void* аргумент, который может указывать на все, что вы хотите. Затем внутри тела функции вы можете вернуть его к соответствующему типу и использовать его рабочим потоком.

В случае, если вашей ветке не нужны никакие дополнительные данные, вы можете передать NULL или nullptr (для C++ 11).

2

Нет, подпись метода, которую вы предлагаете, не будет работать как функция запуска для потока pthreads. Если вы передадите указатель на такую ​​функцию на pthread_create(), тогда компилятор должен предупредить. Если вы запустите результирующую программу, вы вызываете неопределенное поведение, потому что указатель не имеет правильного типа. Как практический вопрос, библиотека pthreads попытается передать аргумент функции start и будет ожидать от него возвращаемое значение; если вы указали указатель на функцию, которая не использует оба аргумента и возвращает значение (оба подходящего типа), то, скорее всего, программа выйдет из строя.

Что касается почему требуется функция запуска, чтобы иметь подпись он делает, void * аргумент может быть использован, чтобы передать фактический аргумент любого типа, в том числе составного типа, охватывающей несколько различных значений, и аналогично, void * тип возврата может использоваться для передачи возвращаемого значения любого типа. Это в значительной степени самый общий тип функции.