Освобождение объектов COM в фоновом потоке - PullRequest
2 голосов
/ 14 февраля 2012

Расширение до Освобождение COM-объекта в C #

Я заметил, что сохранение MailItem и освобождение - это трудоемкая задача.Итак, безопасно ли делать следующее?(псевдокод ниже)

Thread 1 (main thread)
- Open 10 (different .msg files) - MailItems [List<MailItem> items]
- user works on them and want to save and close all of them with one click.

- On_save_All_click (runs on main thread)
- Do
- toBeClearedList.addAll(items);
- items.clear() [so that main thread cannot access those items]
- BG_Thread.ExecuteAsyn(toBeClearedList);
- End

Thread 2 (background thread) (input - List<MailItems>) 
- foreach(MailItem item in input)
    item.save();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(item)
- done

Я написал пару тестов и похоже, что он работает;Просто хотите знать, безопасно ли это делать?«Освобождение объектов COM в потоке, отличном от того, в котором они были созданы»

Спасибо

Karephul

Ответы [ 2 ]

5 голосов
/ 15 февраля 2012

При использовании COM из неуправляемого кода (C / C ++) правила довольно строги: вы можете вызывать методы только на интерфейсе из той же квартиры, на которой вы приобрели объект. Таким образом, если вы получите указатель на интерфейс в потоке STA, то только этому потоку разрешено вызывать любой из методов. Если вы получите указатель на интерфейс в потоке MTA, то этот указатель могут использовать только другие потоки в том же MTA. Любое другое использование, которое пересекает квартиры, требует, чтобы указатель интерфейса был перенесен в другую квартиру.

Тем не менее, это мир без изменений. .Net добавляет целый слой поверх COM, который скрывает много этих низкоуровневых деталей, и по большей части, как только вы получите интерфейс, вы можете передавать этот интерфейс между потоками столько, сколько пожелаете, без приходится беспокоиться о старых правилах потоков. Здесь происходит то, что он фактически передает ссылки на объект, называемый «Runtime Callable Wrapper» (RCW), и управляет базовым интерфейсом COM и соответствующим образом контролирует доступ к нему. (Это берет на себя бремя поддержки правил COM-квартиры, так что вам не нужно, и поэтому может показаться, что старые правила COM-потоков не применяются в .Net: они есть, они просто скрыты от вы.)

Таким образом, вы можете безопасно вызывать Release или другие методы из другого потока: но имейте в виду, что если исходный поток был STA, то вызов этих методов приведет к тому, что базовый RCW перенаправит вызов обратно в исходный поток-владелец, чтобы он все еще поддерживает подчиненные правила COM. Таким образом, использование отдельного потока может на самом деле не дать вам никакой производительности!

Некоторые статьи, достойные прочтения, которые заполняют некоторые детали здесь:

2 голосов
/ 14 февраля 2012

Если я правильно помню свой COM (я всегда ненавидел эту технологию, слишком сложная), если COM-объект является однопоточным (то есть принадлежит однопоточному), его освобождение из другого потока не является 'не принесет вам пользы - он просто выполнит фактический код выпуска в вашем основном потоке.

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

...