Как сделать многопоточную, создание атомарных объектов и обмен - PullRequest
3 голосов
/ 05 апреля 2011

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

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

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

public class WcfDeviceActivationService : IDeviceActivationService {
    ChannelFactory<IDeviceActivationService> _factory = new ChannelFactory<IDeviceActivationService>();
    IDeviceActivationService _channel = null;

    ReaderWriterLockSlim _swaplock = new ReaderWriterLockSlim();

    public WcfDeviceActivationService() {
        _channel = _factory.CreateChannel();
        ((IClientChannel)_channel).Open();
    }

    public Guid ActivateDevice(string activationCode, Guid userId) {
        return Call(c => c.ActivateDevice(activationCode, userId) );
    }

    private RT Call<RT>(Func<IDeviceActivationService, RT> chanfunc) {
        try {
            using(_swaplock.UseReadLock())
                return chanfunc(_channel);
        } catch(Exception) {
            // Get a reference to the channel before attempting the exclusive lock
            var chan = _channel;

            // Take an exclusive lock to block callers while we check the channel
            // (just to prevent excessive failures under heavy call load)
            using (_swaplock.UseWriteLock()) {
                // Let's see if we're still working with the original channel and if it's faulted
                if (Object.ReferenceEquals(chan, _channel) && ((IClientChannel)chan).State == CommunicationState.Faulted) {
                    // It faulted, so lets create a new channel to replace the bad one

                    // If the channel creation throws, the next attempt to use the failed channel
                    //  will take this path again and attempt to create a fresh channel.
                    // We want the creation exception to propagate so that the caller
                    //  knows that their call failed because the channel couldn't be created.
                    var newchan = _factory.CreateChannel();
                    ((IClientChannel)newchan).Open();

                    // Exchange the new channel for the old one
                    // (assigning reference types is atomic, but Exchange also does a memory barrier for us)
                    Interlocked.Exchange(ref _channel, newchan);

                    // Clean up the old channel
                    ((IClientChannel)chan).Abort();
                }
            }

            // Propagate exception to the caller
            throw;
        }
    }
}

ОБНОВЛЕНИЕ

Продумывая упрощение кода благодаря Фредрику и Млаву,Я рефакторинг на это, все еще не уверен, что это полностью правильно или нет.

1 Ответ

3 голосов
/ 05 апреля 2011

Вы можете сделать Interlocked.CompareExchange с мертвым каналом, переданным в качестве сравнения, и новым каналом, переданным как значение.

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

Единственная проблема заключается в том, что вы можете иногда создавать дополнительный канал, который вам просто нужно выбросить после того, как вы обнаружите, что CompareExchange не работает. Это приемлемо в вашей ситуации?

Преимущество заключается в том, что CompareExchange, вероятно, неблокирует (не на 100% уверен, так как я парень на Java, а не .Net. Я основываю это предположение на AtomicReference.compareAndSet ).

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