2016-10-27 4 views
3

У меня есть некоторые встроенные функции ОС, которые мне нужно смоделировать на машине linux. Подход, который мне поручили предпринять, - это перегрузить встроенные функции ОС и обернуть их вокруг потоков POSIX, чтобы машина Linux могла обрабатывать встроенные функции ОС во время модульных тестов и много чего.Указатель функции typedef in c

Встроенная функция ОС, чтобы создать новый поток: OSCreateTask(OStypeTFP functionPointer, OSTypeTcbP taskId, OStypePrio priority)

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

Я надеялся создать ЬурейеЕ, что я мог бы использовать его как:

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, &tFP, NULL); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

но компилятор жалуется, что functionPointer имеет тип void (**)(void), когда pthread_create ожидает void * (*)(void *)

Нужно ли мне каким-либо образом изменить свой тип typedef, или мне нужно сделать некоторое приведение типов? И то и другое?

+0

Функция должна принимать '' недействительным * параметр и возвращать 'аннулируются *' – imreal

+0

Вы должны читать далее о ['pthread_create'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html) и, возможно, о потоках в целом. Так же как указатели на функции и функции распадаются на указатели и то, что делает оператор address с переменной указателя. –

+0

Для «перегрузки» функция (имя) предназначена для предоставления разных функций с тем же именем, но с разными типами аргументов. C не поддерживает это. –

ответ

5

Вам необходима функция адаптера:

typedef void (*OStypeTFP)(void); 

// Function to run task/thread in 
void taskFunction(void) { while(1); } 

void *trampoline(void *arg) 
{ 
    OStypeTFP task = (OStypeTFP)arg; 
    task(); 
    return NULL; 
}  

// Overloaded Embedded OS function 
void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 

    pthread_attr_init(&threadAttrs); 
    pthread_create(&thread, &threadAttrs, trampoline, tFP); 
} 

// Creates a task that runs in taskFunction 
OSCreateTask (taskFunction, id, prio); 

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

+0

@BjornA. Виноват. Благодаря! – Sergio

+0

Ах, ха! Раньше я пробовал что-то подобное, но я попробовал просто вызвать arg() вместо создания новой переменной задачи и затем вызвать task(). Благодаря! – cjameston

+0

@ 2501 Это правда, что C не выполняет _require_ преобразование между указателями функций и объектов, чтобы работать, но это тоже не является _forbid_. И POSIX, который указывает API 'pthread_ *', * does * требует преобразования между указателями функций и 'void *' (в частности) для работы. Поэтому этот ответ совершенно прекрасен, пока нет никаких дополнительных данных, которые необходимо передать в прокладку. Поскольку OP является cagey о том, в какую встроенную ОС они эмулируют, мы не знаем, нужны ли им дополнительные данные. – zwol

3

Если я правильно понял, сигнатура процедуры потока на встроенной ОС равна void thread_proc(void). С другой стороны, для потоков POSIX это void *thread_proc(void *).

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

typedef void (*OStypeTFP)(void); 
struct emu_OSCreateTask_thread_start_data 
{ 
    OStypeTFP real_thread_proc; 
    // possibly other stuff 
}; 

void *emu_OSCreateTask_shim_thread_proc (void *xctx) 
{ 
    struct emu_OSCreateTask_thread_start_data *ctx = xctx; 

    ctx->real_thread_proc(); 
    return 0; 
} 

void OSCreateTask(OStypeTFP tFP, OStypeTcbP tcbP, OStypePrio prio) 
{ 
    pthread_attr_t threadAttrs; 
    pthread_t thread; 
    struct emu_OSCreateTask_thread_start_data *ctx = 
     malloc(sizeof(struct emu_OSCreateTask_thread_start_data)); 

    ctx->real_thread_proc = tFP; 

    pthread_attr_init(&threadAttributes); 
    pthread_create(&thread, &threadAttributes, 
        emu_OSCreateTask_shim_thread_proc, ctx); 
} 

Примечание: ctx выделяется в куче, и утечка, потому что он должен жить только после emu_OSCreateTask_shim_thread_proc возвращения, которое может быть неопределенно позднее, когда OSCreateTask возвращается. Не зная больше об API, который вы пытаетесь подражать, я не могу сказать вам, где вы должны его пишете, чтобы он мог освободиться, когда это необходимо, но, вероятно, есть где-то. Может быть, в tcbP?

Примечание 2: Я использую объект контекста, а не только начинка «real_thread_proc» в контексте указателе pthread_create «s (как в ответе Серджио), потому что я подозреваю, что вы будете наматывать необходимость делать больше вещей в прокладке, и необходимости больше данных из внешнего контекста, чтобы сделать это. (Вы в системе POSIX, так что является безопасно функции вещи указателей в void *.)

+0

Я думаю, мы должны 'free()' 'ctx' перед возвратом из' emu_OSCreateTask_shim_thread_proc() ' – Sergio

+0

@Sergio Не обязательно; это может закончиться необходимостью выжить до эквивалента 'pthread_join'. – zwol

+0

@zwol Это правильный ответ, поскольку он обертывает указатель в структуре. Я не вижу причин не освобождать после вызова функции, поскольку pthread_join ничего не знает о переданном параметре. Совершенно верно, что созданный поток освобождает память. – 2501

Смежные вопросы