Как я могу безопасно передать значение переменной в метод C ++, который будет принимать только void * в качестве аргумента? - PullRequest
0 голосов
/ 26 октября 2019

У меня есть функция, принимающая void* в качестве единственного параметра, а также возвращающая void*: gpioThreadFunc_t

Теперь у меня есть переменная типа track_t , который по сути является unsigned char, и хотел бы вызвать мой метод со значением (!) в качестве параметра. В свою очередь, метод должен убедиться, что аргумент действительно track_t (соответственно unsigned char), и использовать его.

Я попытался вызвать метод следующим образом:

start_thread (Loop, (void *) &track);

… где Loop - имя метода, а track - (локальная) рассматриваемая переменная. При установке его значения на 2, метод получил 0 или 131 или что-то еще, но не 2.

Loop определяется следующим образом:

void *Loop (void *params);

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

Пояснение: Я все еще работаю над своим кодом, так что это НЕ запрос на отладку. Я задаю этот вопрос только для того, чтобы не столкнуться с ловушкой.

Ответы [ 2 ]

2 голосов
/ 26 октября 2019

Если поток на самом деле не нуждается в доступе к самой переменной track (чтобы внести в нее изменения), тогда вам просто нужно передать значение переменной track вместо ее адреса . Значение unsigned char легко помещается в биты указателя void*:

void* Loop(void *params) {
    track_t track = static_cast<track_t>(reinterpret_cast<uintptr_t>(params));
    ...
}

...

track_t track = 2;
start_thread(Loop, reinterpret_cast<void*>(static_cast<uintptr_t>(track)));

В противном случае вы можете динамически выделить track_t для передачи в поток,и затем освободите его до выхода из потока:

void* Loop(void *params) {
    std::unique_ptr<track_t> track(static_cast<track_t*>(params));
    ...
}

...

std::unique_ptr<track_t> track(new track_t(2));
if (start_thread(Loop, track.get()))
    track.release();
1 голос
/ 26 октября 2019

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

Я пытался вызвать метод следующим образом:

start_thread (Loop, (void *) &track);

То, что вы пыталисьсработает, если Loop преобразует указатель void обратно в track_t* и при условии, что указанный track объект остается в живых до тех пор, пока он больше не используется.

Приведение к void* в вашем примере не нужнотем не менее, поскольку все указатели объектов неявно преобразуются в void*.


Как можно безопасно передать ... void *

Невозможносделать функцию, которая принимает void* безопасной. Он по своей природе небезопасен.

Что вы можете сделать, так это написать шаблон-оболочку, которая безопасна для типов и которая не требует непосредственного вызова start_thread. Пример:

template<class T>
using fun_t = T*(T*);

template<auto fun_ptr, class T>
void start_thread_safer(T* params)
{
    auto callback = [](void* vparams) -> void* {
        return fun_ptr(static_cast<T*>(vparams));
    };
    start_thread(callback, params);
}

Теперь вы можете безопасно печатать:

track_t* Loop (track_t* params);
start_thread_safer<Loop>(&track);

Существует оптимизация, позволяющая избежать косвенного обращения: поскольку unsigned char гарантированно подходитв памяти void* вы можете передать объект в эту память напрямую. С целыми числами (такими как unsigned char) это просто:

str::uintptr_t temp = track;
start_thread (Loop, reinterpret_cast<void*>(temp));

// in Loop
track_t track = reinterpret_cast<str::uintptr_t>(params);

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

void* params = nullptr;
static_assert(sizeof params >= sizeof track);
std::memcpy(&params, &track, sizeof track);
start_thread (Loop, params);

// in Loop
track_t track;
std::memcpy(&track, &params, sizeof track); 

Эта оптимизация также повышает безопасность, поскольку больше нет косвенного обращения, и, таким образом, вы больше не можете не поддерживать указанный параметр живым до его использования.

Я оставлю это как упражнениеобъединить эти подходы.

...