Отправка строковых данных между потоками (Win32)

Это довольно простой вопрос, я в основном ищу «лучший практический» подход к тому, что я пытаюсь сделать.

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

В настоящее время я думаю, что использование SendMessage было бы хорошим подходом, используя WM_COPYDATA? Это на правильном пути? Изначально у меня был потокобезопасный класс очереди, который отправлял простые уведомления обратно в поток графического интерфейса, который затем удалял строку из очереди. Однако вскоре я сделал шаг назад и понял, что очередь мне не нужна; Я мог бы просто отправить строку напрямую.

Какие-нибудь советы? Спасибо!

Изменить: И для полноты я использую С++.


person CapBBeard    schedule 09.06.2009    source источник
comment
Ваш исходный метод передачи сообщений на основе очереди является одновременно стандартным и элегантным. Скорее всего, это быстрее и удобнее, чем использование SendMessage.   -  person Tom Leys    schedule 09.06.2009


Ответы (6)


WM_COPYDATA будет работать нормально, но я думаю, что лучше просто определить свое собственное сообщение в приватном окне. Выделите строку в рабочем потоке и освободите ее в потоке графического интерфейса, когда закончите. Используйте PostMessage вместо SendMessage, чтобы не блокировать своего воркера без необходимости.

person Peter Ruderman    schedule 09.06.2009

Как указывали некоторые другие, лучшим подходом здесь может быть пользовательское оконное сообщение.

Еще одна вещь, которую следует учитывать, - это фактическая используемая память. Передавая строку между потоками, я предполагаю, что вы также передаете право собственности на строку между потоками. Это может вызвать несколько проблем, о которых вы должны знать, включая

  • Утечки памяти: что произойдет, если поток A отправит сообщения и, следовательно, отдаст право собственности, но окно будет уничтожено до того, как поток B обработает сообщение
  • Может ли диспетчер памяти, поддерживающий вашу строку, безопасно выделять и освобождать память в разных потоках.

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

person JaredPar    schedule 09.06.2009

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

Если вас волнует простота приложения - придерживайтесь того пути, который легче реализовать. Если дело в производительности - делайте профиль и выбирайте тот вариант, который реально быстрее.

person sharptooth    schedule 09.06.2009

Visual Studio 2010 значительно упрощает такие сценарии благодаря библиотеке асинхронных агентов. Вы можете ознакомиться с пошаговыми руководствами в документации здесь, но вот не такой псевдокод:

//somewhere stateful, e.g. main
unbounded_buffer<stringtype> buff;

//thread 1
{
  //send a message asynchronously to the buffer
  asend(&buff,stringtype("hello world");
}

//thread 2
{
  //get the message out of the buffer
  //if this is a UI thread, receive is blocking so use try_receive which isn't
  stringtype message = receive(&buff)
}

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

person Rick    schedule 10.06.2009

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

person Robert    schedule 09.06.2009

Многое зависит от того, как вы хотите, чтобы информация поступала.

Самым быстрым способом обмена информацией может быть общая переменная с некоторой формой часового для предотвращения условий гонки. Если есть несколько строк, у вас может быть какая-то очередь.

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

person Michael J    schedule 09.06.2009