как использовать postThreadMessage для передачи структуры - PullRequest
4 голосов
/ 20 августа 2011

Я хочу использовать средства очереди сообщений Windows для отправки структуры в другой поток. Но я обнаружил, что функция postthreadmessage предоставляет только два целочисленных параметра, lparam и wparam, для передачи аргументов. Поэтому я решаю поместить адрес структуры в lparam. Это правильный способ, которым окна используют для передачи struct?

И я намерен использовать boost :: shared_ptr для хранения адреса struct как в потоке получателя, так и в потоке отправителя. Я сомневаюсь, что когда два shared_ptr выйдет из области видимости, будет ли структура освобождена дважды? Я не могу найти способ гарантировать, что структура, выделенная в куче, будет освобождена на 100%. Есть идеи?

Ответы [ 2 ]

0 голосов
/ 20 августа 2011

Я сталкивался с подобной ситуацией, используя класс Qt QModelIndex, который хранит данные, используя void*, но я управляю данными, на которые он указывает, используя shared_ptr.

Чтобы избежать разыменования void* напрямую, которое может указывать на более не существующий объект, я использую карту от void* до weak_ptr. Все объекты, на которые ссылается QModelIndexes, хранятся на карте. Когда приходит время разыменования void*, я использую void* в качестве ключа для извлечения соответствующего weak_ptr с карты, а затем преобразую weak_ptr в shared_ptr. shared_ptr тогда либо равен void*, либо NULL, и вы также получаете безопасность типов.

Обратите внимание, что моему решению не приходилось сталкиваться с упомянутыми вами проблемами параллелизма, но вы можете адаптировать его к вашей ситуации. Вы можете использовать lparam для хранения необработанного указателя на ваш объект, а затем использовать карту для преобразования необработанного указателя в интеллектуальный указатель. Защитите карту мьютексом, и вы можете быть там.

0 голосов
/ 20 августа 2011

На первый вопрос, да, LPARAM предназначен для использования в качестве целого числа или указателя.Это ясно из определения:

typedef LONG_PTR LPARAM;

Это целое число, достаточно длинное, чтобы содержать указатель.

Что касается элемента shared_ptr, вы правы, если вы передадите необработанный указатель и обернетесьэто в другой shared_ptr, вы освободите его дважды:

shared_ptr<Thing> a;
PostThreadMessage(x, 0, (LPARAM)a.get());
...
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp)
{
    shared_ptr<Thing> p((Thing*)lp); //Bad!!!
}

Но вместо этого вы можете попробовать этот обходной путь:

shared_ptr<Thing> a;
PostThreadMessage(x, 0, new shared_ptr<Thing>(a)); //pointer to smart-pointer
...
LRESULT OnMessage(int msg, WPARAM wp, LPARAM lp)
{
    shared_ptr<Thing> *pp = (shared_ptr<Thing>*)lp;
    shared_ptr<Thing> p(*pp);
    delete pp; //no leak
}

AFTERTHOUGHT : обратите внимание, что PostThreadMessage может завершиться ошибкой.... и вы не хотите пропускать shared_ptr.

По моему опыту, обычно лучше использовать std :: deque для хранения данных и использовать PostThreadMessage для уведомления о том, что там есть данные.Таким образом, вы никогда не потеряете объект!YMMV

...