2015-03-03 2 views
2

Я знаю, что есть много ответов на вопросы о литье void * в struct, но я не могу заставить его работать правильно.C - cast void * to structure in thrd_create()

Ну, я хочу создать нить, которая будет воспроизводить музыку в фоновом режиме. У меня есть структура, которая собирающая заряженный массив музыкальных файлов и индекс начала и конца:

typedef unsigned char SoundID; 
typedef unsigned char SongID; 

typedef struct { 
    Mix_Music *songs[9]; // array of songs 
    SongID startId;  // index of first song to play 
    SongID endId;  // index of last song to play 
} SongThreadItem; 

Тогда я хочу играть песни, создавая поток и передавая функцию, которая на самом деле играет песню функции thread_create().

int play_songs(Mix_Music *songs[9], SongID startId, SongID endId, char loop){ 
    thrd_t thrd; 
    SongThreadItem _item; 
    SongThreadItem *item = &_item; 

    memcpy(item->songs, songs, sizeof(item->songs)); 
    item->startId = startId; 
    item->endId = endId; 
    printf("item->startId is %i\n", item->startId); 
    printf("item->endId is %i\n", item->endId); 
    thrd_create_EC(thrd_create(&thrd, audio_thread_run, item)); 

    return 0; 
} 

int audio_thread_run(void *arg){ 
    SongThreadItem *item = arg; // also tried with = (SongThreadItem *)arg 

    printf("item->startId is %i\n", item->startId); 
    printf("item->endId is %i\n", item->endId); 
    free(item); 

    return 0; 
} 

Тогда я получаю следующий результат:

item->startId is 0 
item->endId is 8 
item->startId is 6 
item->endId is 163 

значение извлекается внутри audio_thread_run() являются не один ожидать. Я не знаю, поставил ли я достаточно кода, чтобы кто-то нашел мою ошибку, я стараюсь сделать его минимальным, потому что это часть более крупного проекта.

Заранее за вашу помощь.

+1

Вы передаете указатель ('item') на автоматический объект (' _item'). К тому времени, когда поток работает, объект уже мертв. Вызов 'free' на то, что не было выделено с помощью' malloc', также является no-no. – molbdnilo

ответ

2

Поток работает асинхронно, но вы передаете ему указатель на SongThreadItem, который находится в стеке потока, который вызывает play_songs().

Если у вас есть только один поток, призывающую play_songs() и это не вызывается снова, пока вы не закончите с item, вы можете сделать определение _item так:

static SongThreadItem _item; 

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

Если вы не знаете, кто и когда будет вызывать play_songs() тогда только malloc в _item и free его в потоке, когда вы сделали:

... 
SongThreadItem *item = (SongThreadItem *)malloc(sizeof(SongThreadItem)); 
... 

Последнее, как правило, лучшая идея. Подумайте об этом, передав владение данными в новый поток. Конечно, код качества продукции должен освобождать элемент, если создание потока не выполняется.

+1

Или, как обычно, 'item = malloc (sizeof * item);'. [Нет броска] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc), не повторяющееся имя типа, намного короче. Намного лучше. – unwind

3
SongThreadItem _item; 
SongThreadItem *item = &_item; // bug 

Это проблема: вы передаете поток указателю на переменную стека. Стек будет перезаписано почти все, что происходит в основном потоке. Здесь вам нужно выделить динамическую память (с malloc) и позаботиться о ее освобождении, когда она больше не нужна (возможно, в самой процедуре потока).

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