Как будет вести себя блокировка в .net? - PullRequest
3 голосов
/ 28 ноября 2008
abstract class Foo
{
    private List<Object> container;
    private bool update;

    Foo Foo()
    {
        container = new List<object>();
        update = false;
    }

    public abstract Bar CreateBar();

    public void BeginUpdate()
    {
        if (!update)
        {
            Thread update_thread = new Thread(new ThreadStart(Update));
            update_thread.Start();
        }
    }

    private void Update()
    {
        update = true;
        while (update)
        {
            lock (container)
            {
                if (...)
                    container.Add(this.CreateBar());
                else
                    container.Remove(...);
            }

            Thread.Sleep(1337);
        }
    }

    public void EndUpdate()
    {
        update = false;
    }

    public List<Object> Objects
    {
        get
        {
            lock (container)
            {
                return this.container;
            }
        }
    }
}

Когда что-то вне Foo вызывает метод доступа к объекту Foo, например,

List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{
    Thread.Sleep(31173);
}

Как будет происходить блокировка? Придется ли потоку, выполняющему Update (), ждать, пока вышеупомянутый foreach не завершит обработку списка объектов? Я хотел бы, чтобы эти два работали одновременно, является ли единственным решением сделать глубокую копию объектов?

Ответы [ 4 ]

3 голосов
/ 28 ноября 2008

Несколько проблем с этим кодом:

  1. Вы не запускаете тему
  2. У вас может быть условие гонки (может быть неприменимо к вашей программе), когда несколько потоков вызывают BeginUpdate, оба видят, что обновление ложно, и оба запускают поток, теперь у вас есть два работающих потока, возможно мешающих друг другу , так как у вас есть член поля с общими данными
  3. Какой смысл блокировки в собственности? Тебе это не нужно. Обратите внимание, что контейнер, который вы возвращаете из свойства, иногда будет находиться в состоянии изменения из-за внутреннего обновления. Это означает, что внешний код, который вызывает свойство, должен будет заблокировать сам контейнер перед доступом к его содержимому. Вам не нужна блокировка для возврата ссылки на контейнер.
  4. Состояние гонки, если вы вызываете EndUpdate, а затем BeginUpdate сразу после друг друга, старый поток может еще не иметь возможности выйти

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

2 голосов
/ 28 ноября 2008

Ваш код не делает то, что вы думаете, что он делает. Этот метод

public List<Object> Objects
{
    get
    {
        lock (container)
        {
            return this.container;
        }
    }
}

Не удерживает блокировку после возвращения значения. Таким образом, ваш цикл не заблокирован.

Вы не можете вернуть экземпляр контейнера из класса

1 голос
/ 28 ноября 2008

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

Таким образом, и цикл, и поток будут иметь доступ к объектам одновременно. Это плохо, потому что если ваш поток изменяет объекты во время цикла, цикл вызовет исключение, потому что коллекция была изменена.

0 голосов
/ 28 ноября 2008

krosenvald является верным, блокировка доступа к объектам снимается, как только свойство возвращает указатель на объект контейнера ...

В вашем коде

List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{    
    Thread.Sleep(31173);
}

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

...