Отправка строковых данных между потоками (Win32) - PullRequest
0 голосов
/ 09 июня 2009

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

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

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

Есть советы? Спасибо!

Редактировать: И для полноты я использую C ++.

Ответы [ 6 ]

2 голосов
/ 09 июня 2009

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

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

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

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

2 голосов
/ 09 июня 2009

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

1 голос
/ 10 июня 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)
}

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

1 голос
/ 09 июня 2009

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

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

0 голосов
/ 09 июня 2009

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

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

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

0 голосов
/ 09 июня 2009

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

...