2015-10-11 4 views
0

Я пытаюсь выяснить способ заставить мою программу производить два звуковых сигнала одновременно с использованием функции Beep() в библиотеке windows.h. Я решил сделать это, используя пару pthreads. Тем не менее, у меня возникла проблема с созданием допустимого набора аргументов.Как правильно передать аргумент pthread

Я довольно новичок в программировании и мало знаю о type_casting или void * синтаксисе/правилах/целях. Я знаю, что это указатель на данные любого типа. Я хотел бы как можно больше понять многопоточность и void * s, поскольку они кажутся очень полезными. Если кто-то может предложить некоторые хорошие статьи или учебные пособия (сделанные с учетом новичка), я был бы очень признателен.

#include <iostream> 
#include <pthread.h> 
#include <windows.h> 
using namespace std; 



void *tone(void *note) 
{ 
    double freq; 
    freq = double(note); 
    Beep(freq, 5000); 
} 

int main() 
{ 
    double C5 = 523.25; 
    double D5 = 587.33; 
    double E5 = 659.25; 
    double F5 = 698.46; 
    double G5 = 783.99; 
    double A5 = 880.00; 
    double B5 = 987.77; 
    double C6 = 1046.50; 

    pthread_t tone1; 
    pthread_t tone2; 

    pthread_create(&tone1, NULL, tone, (void *) C5); 

} 

Кроме того, я надеюсь, что мои кодовые сообщения правильно. Я только сделал это раньше.

+0

Это очень поможет, если вы пометите это на каком языке вы используете. Но, как правило, простой шаблон заключается в создании 'struct', который содержит все параметры, необходимые для передачи в поток. Выделите экземпляр этой структуры, заполните ее, передайте указатель на нее в поток и разрешите потоку освободить ее, когда она будет выполнена с ней. –

ответ

4

Прежде всего, вы должны знать, что библиотека pthread (aka POSIX threads) представляет собой библиотеку потоков для систем POSIX, которая в наши дни является самой современной операционной системой. кроме для Windows; но <windows.h> - это очень большой заголовок только для Windows, поэтому вы никогда не должны смешивать их в одной и той же программе, если только вы не развиваетесь против уровня эмуляции или совместимости или подобного (например, с Cygwin в Windows или с Wine in Linux).

Независимо от того, какую библиотеку потоков вы используете, ответ остается тем же. Оба POSIX pthread_create() и Windows CreateThread()/_beginthreadex() принимают параметр void*, который передается вашей процедуре потока. Но вам не нужно фактически передавать реальное значение указателя, если вы этого не хотите - ОС рассматривает его как непрозрачный blob и передает его без изменений. Таким образом, пока данные, которые вы хотите передать, не больше, чем указатель, вы можете просто перенести его на указатель на пути и отбросить его обратно с другой стороны.

Например, если вы хотите передать целое число процедуры резьбы:

int theAnswer = 42; 
pthread_create(..., &thread_proc, (void *)(intptr_t)theAnswer); 
... 
void *thread_proc(void *param) { 
    int theAnswer = (int)(intptr_t)param; // Contains 42 
    ... 
} 

Ваш пример передает значение double, который на 64-битных системах, вероятно, будет такой же размер, как указатель, так что вы могли бы снять тот же трюк, например с union; но он, безусловно, будет больше, чем указатель на 32-битных системах.

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

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

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

Вот пример, который будет работать независимо от того, больше или меньше double, чем указатель (т., как 32-битные, так и 64-битные системы):

// Allocate dynamic memory for the thread parameter. If you want to pass more 
// than one value, create a struct instead. 
double *theAnswer = new double(42.0); 
pthread_create(..., &thread_proc, theAnswer); 
... 
void *thread_proc(void *param) { 
    // Order of operations here is important: dereference the value first, then 
    // free the memory 
    double *theAnswerPtr = (double *)param; 
    double theAnswer = *theAnswer; 
    delete theAnswerPtr; 
    // theAnswer is now 42.0, use it 
    ... 
} 
Смежные вопросы