2009-12-22 6 views
0

Я реализую высокопроизводительный поточно-безопасный компонент без использования операторов блокировки, только по соображениям производительности используются только изменчивые и блокированные.Определяет, когда объект не используется ни одним другим потоком без блокировки?

У меня есть элемент volatile reference-type в классе, который содержит потокобезопасный экземпляр. Этот экземпляр является потокобезопасным только для нескольких операций, а не для другого. Из-за этого и по соображениям производительности, в некоторых случаях я предпочитаю создавать новый экземпляр вместо обновления оригинала, и он действительно работает быстрее, особенно потому, что я не использую никаких операторов блокировки.

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

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

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

Как я могу гарантировать, что нет потока, который использует старый экземпляр без операторов блокировки? (летучие и взаимоблокированные)

Спасибо.

+3

делает, используя блокировку действительно значительно снижает производительность? – ironic

+0

Мне очень нравится это слово «детерминировано», и мне нужно запомнить этот. –

+1

Если вам нужен контроль мелкой зернистости по управлению памятью, управляемое приложение, вероятно, не подходит для правильного пути. Что вы делаете, когда вы блокируете, это штраф за производительность? – GrayWizardx

ответ

1

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

Как правило, вам не следует пытаться работать с сборщиком мусора .NET. Лучше будет узнать, почему GCs занимают так много времени и оптимизируют для этого (не создавайте так много экземпляров в первом место, возможно, операция O (n^2), создающая множество экземпляров?) вместо того, чтобы пытаться повторно использовать экземпляры поточно-безопасным способом.

+0

множество экземпляров создаются по дизайну, это должно быть так. если бы я мог перерабатывать экземпляры, поэтому сбор мусора вообще не понадобился. – DxCK

0

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

+0

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

2

То, что вы пытаетесь реализовать, выглядит так же, как подсчет ссылок (помните COM?). Вероятно, вы можете сделать это с помощью приращений/декрементов - просто держите контрольный счетчик рядом с вашей ссылкой.

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

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

+0

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

+0

Неверно, что доступ к volatile подразумевает барьер, предполагая, что volatile имеет ту же семантику в модели памяти C#, что и Java-процессоры, такие как все процессоры x86, имеют достаточно сильную семантику видимости памяти, которая * читает * доступ к летучести не требует особых семантика на уровне ЦП - только для записи требуется команда с барьером/блокировкой (разумеется, на уровне байт-кода как чтение, так и запись имеют специальную семантику, разрешающую переупорядочение и т. д.). – BeeOnRope

0

Вы можете восстановить объект из мертвых, т. Е. Когда ваши объекты завершены , вы на самом деле их снова оживите.Это имеет то преимущество, что на этом этапе их жизненного цикла не может быть никакой ссылки на них, иначе они никогда не были бы применимы для окончательной доработки. Более подробную информацию смотрите в главе «Ressurection» в статье this.

Теперь, если это на самом деле покупает вам любую работу, или если это стоит делать это, я не могу сказать ;-)