2013-04-26 2 views
7

Это моя первая попытка потоковой передачи в C. Я создаю круговой буфер. Я знаю, как создать нить, но все примеры, которые я видел только у резьбовых функций, которые принимают один параметр недействительного, но, к сожалению спецификация моего работника требует от меня, чтобы использовать три, как показано здесь:Передача нескольких аргументов в поточную функцию из pthread_create

void bufferRead(BoundedBuffer* buffer, char* data, int count) { 
    pthread_mutex_lock(&buffer->mutexBuffer); 
    <snip> 
    pthread_mutex_unlock(&buffer->mutexBuffer); 
} 

Вот мой pthread_create заявление

pthread_create(&buffer.readThread, NULL, (void *)bufferRead, &readParams) 

И мои readParams структура/присвоений

struct readThreadParams {             
    BoundedBuffer b;               
    char* data;                
    int count;                
};                   

struct readThreadParams readParams;           
readParams.b = buffer2;              
readParams.data = out_array;             
readParams.count = in_size; 

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

ответ

8

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

#include <pthread.h> 
#include <stdlib.h> 

struct BoundedBuffer { 
    pthread_t readThread; 
    pthread_mutex_t mutexBuffer; 
} buffer2; 

struct readThreadParams { 
    struct BoundedBuffer b; 
    char* data; 
    int count; 
}; 

void *bufferRead (void *context) { 
    struct readThreadParams *readParams = context; 

    pthread_mutex_lock(&readParams->b.mutexBuffer); 
    //<snip> 
    pthread_mutex_unlock(&readParams->b.mutexBuffer); 

    return NULL; 
} 

int main(void) { 
    int ret; 
    char *out_array = malloc(42); 
    size_t in_size = 42; 

    struct readThreadParams readParams; 
    readParams.b = buffer2; 
    readParams.data = out_array; 
    readParams.count = in_size; 

    /* I presume that by "buffer", you really meant the .b member of 
    * struct readThreadParams. Further, this must have a member 
    * named readThread of type pthread_t, etc. 
    */ 
    ret = pthread_create(&readParams.b.readThread, NULL, bufferRead, &readParams); 

    if (!ret) { 
     pthread_join(&readParams.b.readThread, NULL); 
    } 

    free(out_array); 

    return ret; 
} 
+5

-1 перенос локальной переменной в другой поток –

+0

Если это локальная переменная в main, это не проблема. Если вы выходите из main, ваша программа в любом случае завершается, поэтому переменная всегда существует, пока ваша программа запущена. – jcoder

+1

@jcoder Выход из 'main' не означает немедленного завершения программы. А автоматическая (не куча, нестатическая) переменная для межпоточной связи в лучшем случае является сомнительной. –

1

Вы получили правильный путь.

Прототип функции должен быть как

void* bufferRead(void *arg) 
{ 
    .... 
} 

И типаж аргумент для требуемого типа в функции потока. Здесь должно быть

void* bufferRead(void *arg) 
{ 
    struct readThreadParams *input = (struct readThreadParams*)arg; 
} 

Передача более одного аргумента функции pthread невозможна напрямую. поэтому в основном формируется как структура и передается функции.

См. this учебное пособие для получения более подробной информации о pthreads.

+0

Спасибо за быстрый ответ! Просто интересно, но есть ли способ использовать прототип функции, который у меня есть? – ChrisDevWard

+0

вы можете придумать и создать. Но бесполезно. поэтому рекомендуется 'void *() (void *)'. – Jeyaram

+0

@ChrisDevWard Нет, вы не можете.Ну, единственный способ использовать этот прототип - вызывать его прямо из вашей функции void * start_routine (void *), которую будет вызывать библиотека pthread, но это бесполезно вводит накладные расходы на другой вызов функции. –

4

Функция запуска должна принимать аргумент. Так что ваше направление является правильным:

struct readThreadParams {             
    BoundedBuffer *b; 
    char *data;                
    int count;                
};  

Затем необходимо выделить переменную в куче, а не на стеке:

struct readThreadParams *readParams; 

readParams = malloc(sizeof(*readParams)); 
readParams->b = buffer2;              
readParams->data = out_array;             
readParams->count = in_size; 

После чего вы можете дать ему createThread:

pthread_create(&buffer.readThread, NULL, bufferRead, readParams); 

Функция резьбы должна принимать только 1 аргумент (void *):

void *bufferRead(void *arg) 
{ 
    struct readThreadParams *params = arg; 
    BoundedBuffer *buffer = params->b; 
    char* data = params->data; 
    int count = params->count; 

    pthread_mutex_lock(&buffer->mutexBuffer); 
    <snip> 
    pthread_mutex_unlock(&buffer->mutexBuffer); 

    return NULL; 
} 
0

Этот пример граничит с злоупотреблениями препроцессора, но мне это нравится, потому что он демонстрирует сопоставление значений аргументов по умолчанию.

#include <assert.h> 
#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef char *BoundedBuffer; 

struct read_thread_param { 
    pthread_t thread;             
    BoundedBuffer buffer;               
    char* data;                
    int count;                
}; 

void buffer_read(BoundedBuffer* buffer, char* data, int count) { 
    pthread_mutex_lock(&buffer->mutexBuffer); 
    /*snip*/ 
    pthread_mutex_unlock(&buffer->mutexBuffer); 
} 

void *buffer_read_entrance(void *object) { 
    struct read_thread_param *param = object; 
    if (param->thread != 0) { 
     buffer_read(&param->buffer, param->data, param->count); 
     free(param); 
     return NULL; 
    } 

    param = malloc(sizeof *param); 

    /* TODO: Handle allocation error */ 
    assert(param != NULL); 

    memcpy(param, object, sizeof *param); 

    /* TODO: Handle thread creation error */ 
    assert(pthread_create(&param->thread, NULL, buffer_read_entrance, param) == 0); 
    return NULL; 
} 

#define buffer_read_entrance(...) buffer_read_entrance(&(struct read_thread_param) { .thread = 0, __VA_ARGS__ }) 
void buffer_read(BoundedBuffer* buffer, char* data, int count); 

int main(void) { 
    buffer_read_entrance(.buffer = "hello world", .count = 42); 
} 
Смежные вопросы