Синхронизация коллекции !!!
От: Аноним  
Дата: 20.02.07 07:53
Оценка:
Понятно, что с помощью свойства 'SyncRoot' коллекции, можно получить ссылку на синхронизируемый обьект и использовать её в lock(). Но, цитирую: "Для обеспечения корректной работы коллекции в многопоточной среде часто бывает удобно не делать синхронизацию вручную, а воспользоваться оберткой вокруг коллекции, обеспечивающей синхронизацию доступа к коллекции.". Если я правильно понял, то речь идет о методе который в качестве параметра принимает коллекцию подлежащую синхронизации. И где-то я его видел. Или у меня глюки уже В общем, что имеется в виду под "оберткой вокруг коллекции".
Re: Синхронизация коллекции !!!
От: ksg71 Германия  
Дата: 20.02.07 07:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Понятно, что с помощью свойства 'SyncRoot' коллекции, можно получить ссылку на синхронизируемый обьект и использовать её в lock(). Но, цитирую: "Для обеспечения корректной работы коллекции в многопоточной среде часто бывает удобно не делать синхронизацию вручную, а воспользоваться оберткой вокруг коллекции, обеспечивающей синхронизацию доступа к коллекции.". Если я правильно понял, то речь идет о методе который в качестве параметра принимает коллекцию подлежащую синхронизации. И где-то я его видел. Или у меня глюки уже В общем, что имеется в виду под "оберткой вокруг коллекции".



например Hashtable.Synchronized()
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[2]: Синхронизация коллекции !!!
От: Аноним  
Дата: 20.02.07 08:21
Оценка:
Здравствуйте, ksg71, Вы писали:

K>например Hashtable.Synchronized()


Во-во, точно, что-то вроде этого и видел. А тоя думал глюки
Re[2]: Синхронизация коллекции !!!
От: Аноним  
Дата: 20.02.07 08:42
Оценка:
Здравствуйте, ksg71, Вы писали:

K>например Hashtable.Synchronized()



Попробовал синхронизировать коллекцию с помощью ArrayList.Synchronized() — не получилось Синхронизация проходит только с lock (Collection.SyncRoot). Может я чего-то не понимаю

using System;
using System.Threading;
using System.Collections;

//Программа демонстрирует синхронизацию доступа 3-х потоков к коллекции ArrayList
//Каждый поток печататет содержимое коллекции, ищет определенный элемент, удаляет его, и вставляет три новых на его место,
//после чего печатает результат

class МойПоток
{
    Thread thrd;
    IList Collection;

    int Найти;
    int[] Заменить;

    public МойПоток(IList _collection, string _name, int _Найти, params int[] _Заменить)
    {
        thrd = new Thread(new ThreadStart(this.Run));
        Collection = ArrayList.Synchronized(_collection);  //Так не работает...
        thrd.Name = _name;

        Найти = _Найти;
        Заменить = _Заменить;

        thrd.Start();
    }

    public void PrintCollection()
    {
        Console.Write(thrd.Name + ": ");

        foreach (object El in Collection)
        {
            Console.Write("|{0,4}",El);
        }
        Console.WriteLine("|");
    }

    private void Run()
    {
        //SyncRoot - ссылка на обьект подлежащий синхронизации, т.к. коллекция скрывает детали реализации 
        //и мы не знаем по какому обьекту нужно выполнять синхронизацию !!!

        //Collection = ArrayList.Synchronized(this.Collection); ...и так

        //lock (Collection.SyncRoot)     //Вариант #1
        {
            this.PrintCollection();

            Thread.Sleep(10);

            int idx = Collection.IndexOf(Найти);
            Collection.RemoveAt(idx);
            for (int i = 0; i < Заменить.Length; i++) Collection.Insert(idx, Заменить[i]);

            this.PrintCollection();
        }
    }

    public void JOIN()
    {
        thrd.Join();
        return;
    }
}

class Синхронизация_Коллекции
{
    public static void Main()
    {
        ArrayList Arr = new ArrayList(10);

        Arr.Add(5);
        Arr.Add(0);
        Arr.Add(-7);
        Arr.Add(3);
        Arr.Add(1);
        Arr.Add(27);
        Arr.Add(-12);
        Arr.Add(0);
        Arr.Add(7);
        Arr.Add(9);

        //Arr = ArrayList.Synchronized(Arr);  ...и так тоже не работает
        Console.WriteLine(" Синхронизация : " + Arr.IsSynchronized);

        МойПоток Поток_1 = new МойПоток(Arr, "Поток_1", -7, new int[] { 11, 8, 2 });
        МойПоток Поток_2 = new МойПоток(Arr, "Поток_2", 2, new int[] { 22, 18, 31 });
        МойПоток Поток_3 = new МойПоток(Arr, "Поток_3", 18, new int[] { -1, -37, 17 });

        Поток_1.JOIN();
        Поток_2.JOIN();
        Поток_3.JOIN();
    }
}
Re[3]: Синхронизация коллекции !!!
От: _FRED_ Черногория
Дата: 20.02.07 09:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Попробовал синхронизировать коллекцию с помощью ArrayList.Synchronized() — не получилось Синхронизация проходит только с lock (Collection.SyncRoot). Может я чего-то не понимаю


Похоже не понимашь у тебя неправильная синхронизация и мне совсем не понятно, зачем тебе в таком коде потоки. Напиши словами, чего ты хочешь добиться. По той логике, что вижу в твоём коде я, потоки у тебя должны работать синхронно — то есть сначала один, потом второй, потом тертий. Иначе происходит исключение.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Синхронизация коллекции !!!
От: Аноним  
Дата: 20.02.07 09:13
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Похоже не понимашь у тебя неправильная синхронизация и мне совсем не понятно, зачем тебе в таком коде потоки. Напиши словами, чего ты хочешь добиться. По той логике, что вижу в твоём коде я, потоки у тебя должны работать синхронно — то есть сначала один, потом второй, потом тертий. Иначе происходит исключение.


Обрати внимание:

 private void Run()
 {
 ...
 Thread.Sleep(10); //Даем время стартовать следующему потоку
 ...
 }


Если от комментировать 'lock (Collection.SyncRoot)', то потоки будут выполняться как надо. А вот сделать то-же самое используя ArrayList.Synchronized() неполучается.

Логика в том, что это просто пример на тему 'как синхронизировать коллекцию'. Вот я и спрашиваю с помощью lock(), потоки синхронизируются. А с помощью ArrayList.Synchronized() — нет! Почему?

Кстати в каком месте у меня не правильная синхронизация?

Хочу добиться что-бы потоки выполнялись синхронно используя, ArrayList.Synchronized().
Re[3]: Синхронизация коллекции !!!
От: ksg71 Германия  
Дата: 20.02.07 09:32
Оценка:
Здравствуйте, Аноним, Вы писали:


ArrayList.Syncronized возвращает SyncArrayList (обертка)
а он сихронизирует доступ к внутреннему списку только на уровне метода
к примеру


public override void RemoveAt(int index)
{
      lock (this._root)
      {
            this._list.RemoveAt(index);
      }
}


поэтому в твоем случае без внешнего лока не обойтись
Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[4]: Синхронизация коллекции !!!
От: Аноним  
Дата: 20.02.07 09:43
Оценка:
Здравствуйте, ksg71, Вы писали:

K>ArrayList.Syncronized возвращает SyncArrayList (обертка)

K>а он сихронизирует доступ к внутреннему списку только на уровне метода

Что-то я не понял, что значит 'сихронизирует доступ к внутреннему списку только на уровне метода'? Как тогда его использовать с несколькими потоками?
Можно поподробнее
Re[5]: Синхронизация коллекции !!!
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 20.02.07 09:51
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, ksg71, Вы писали:


K>>ArrayList.Syncronized возвращает SyncArrayList (обертка)

K>>а он сихронизирует доступ к внутреннему списку только на уровне метода

А> Что-то я не понял, что значит 'сихронизирует доступ к внутреннему списку только на уровне метода'? Как тогда его использовать с несколькими потоками?

А>Можно поподробнее

Это значит, что методы будут вида:

public override void CopyTo(Array array)
{
      lock (this._root)
      {
            this._list.CopyTo(array);
      }
}


А вообще-то смотрите рефлектором SyncArrayList.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Синхронизация коллекции !!!
От: _FRED_ Черногория
Дата: 20.02.07 10:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А> Обрати внимание:

А> private void Run()
А> {
А> ...
А> Thread.Sleep(10); //Даем время стартовать следующему потоку
А> ...
А> }

Это не синхронизация, а х… б… ё… Ясно?

А> Если от комментировать 'lock (Collection.SyncRoot)', то потоки будут выполняться как надо. А вот сделать то-же самое используя ArrayList.Synchronized() неполучается.


Потому что есть разница в том, что бы залочить весь список на время всех операций и в том, что бы лосить список на время каждой операции. Чуешь? Во втором случае какие-то (из других потоков) операции могут пролезть между "твоими" (из текущего потока) операциями. Из-за этого-то твоя логика и не выполняется.

А> Кстати в каком месте у меня не правильная синхронизация?

А> Thread.Sleep(10); //Даем время стартовать следующему потоку

Такие вещи говорят исключительно о не хороших сторонах автора

А> Хочу добиться что-бы потоки выполнялись синхронно используя, ArrayList.Synchronized().


Для данной операции ArrayList.Synchronized тебе не подойдёт. Он полезен в других случаях. например, если все элементы, которые надо отыскать заранее были юы в списке, то оно помоглобы. Сейчас — нет.
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Синхронизация коллекции !!!
От: Nikolay_P_I  
Дата: 20.02.07 15:12
Оценка:
Здравствуйте, ksg71, Вы писали:

K>ArrayList.Syncronized возвращает SyncArrayList (обертка)

K>а он сихронизирует доступ к внутреннему списку только на уровне метода
K>к примеру

В связи с этим вопрос — а итератор оно синхронизирует ?

В смысле — foreach(...) по такой коллекции рухнет, если кто-то в ином потоке .Add() в нее захочет ?
Re[5]: Синхронизация коллекции !!!
От: ksg71 Германия  
Дата: 21.02.07 07:42
Оценка: +1
Здравствуйте, Nikolay_P_I, Вы писали:

N_P>Здравствуйте, ksg71, Вы писали:


K>>ArrayList.Syncronized возвращает SyncArrayList (обертка)

K>>а он сихронизирует доступ к внутреннему списку только на уровне метода
K>>к примеру

N_P>В связи с этим вопрос — а итератор оно синхронизирует ?


N_P>В смысле — foreach(...) по такой коллекции рухнет, если кто-то в ином потоке .Add() в нее захочет ?


MSDN

Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.

Das Reich der Freiheit beginnt da, wo die Arbeit aufhört. (c) Karl Marx
Re[6]: Синхронизация коллекции !!!
От: Аноним  
Дата: 21.02.07 08:17
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Это не синхронизация, а х… б… ё… Ясно?


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

_FR>Потому что есть разница в том, что бы залочить весь список на время всех операций и в том, что бы лочить список на время каждой операции. Чуешь? Во втором случае какие-то (из других потоков) операции могут пролезть между "твоими" (из текущего потока) операциями. Из-за этого-то твоя логика и не выполняется.


Имеешь в виду, что другие потоки могут выполнить свои операции между вызовами IndexOf(), RemoveAt() и Insert()? Тоесть планировщик задач ОС может заставить переключиться потоки в момент когда текущий поток вышел из метода и его lock()-блока? Но тогда получается, что "синхронизация оберткой", прокатывает только в том случае если все потоки юзают ОДИН метод? Т.к. если используются два метода Коллекции, все равно между ними может произойти переключение задач?

_FR>Такие вещи говорят исключительно о не хороших сторонах автора


Ну хорошо тогда покажи мне как еще проще заставить потоки переключаться? Это-же просто тестовый пример, а не коммерческое приложение

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


Ну опять-же, это утвержедние имеет смысл, если все потоки пользуются ЕДИНСТВЕННЫМ методом для поиска в Коллекции.

А кстати, метод Add() вообще синхронизируется?
Re[7]: Синхронизация коллекции !!!
От: _FRED_ Черногория
Дата: 21.02.07 08:51
Оценка:
Здравствуйте, <Аноним>, Вы писали:

_FR>>Это не синхронизация, а х… б… ё… Ясно?

А> Ясен пень это не синхронизация, это возможность для переключения потоков, что-бы посмотреть как они синхронизируются

Смотрии далее (*).

_FR>>Потому что есть разница в том, что бы залочить весь список на время всех операций и в том, что бы лочить список на время каждой операции. Чуешь? Во втором случае какие-то (из других потоков) операции могут пролезть между "твоими" (из текущего потока) операциями. Из-за этого-то твоя логика и не выполняется.


А> Имеешь в виду, что другие потоки могут выполнить свои операции между вызовами IndexOf(), RemoveAt() и Insert()? Тоесть планировщик задач ОС может заставить переключиться потоки в момент когда текущий поток вышел из метода и его lock()-блока?


Да.

А>Но тогда получается, что "синхронизация оберткой", прокатывает только в том случае если все потоки юзают ОДИН метод? Т.к. если используются два метода Коллекции, все равно между ними может произойти переключение задач?


Вовсе нет. Смотрии далее (**).

_FR>>Такие вещи говорят исключительно о не хороших сторонах автора

А> Ну хорошо тогда покажи мне как еще проще заставить потоки переключаться? Это-же просто тестовый пример, а не коммерческое приложение

(*) Делают это с помощью объектов синхронизации — событий, например.

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

А> Ну опять-же, это утвержедние имеет смысл, если все потоки пользуются ЕДИНСТВЕННЫМ методом для поиска в Коллекции.
А> А кстати, метод Add() вообще синхронизируется?

(**) Эти методы имеют смысл, когда работа потока с коллекцией не зависит от того, как другие потоки работают с той же коллекцией. У тебя — зависит. В твоём примере (если убрать порнографический Sleep) нельзя заранее сказать, из каких элементов будет состоять коллекция в конце работы программы. И это при том, что все входные данные заранее (состояние коллекции, искомы элементы и их замена) известны. Из-за того, что работа планировщика непредсказуема. В твоём примере вообще потоки не нужны — все операции должны делаться синхронно.
... << RSDN@Home 1.2.0 alpha rev. 675>>
Now playing: «Тихо в лесу…»
Help will always be given at Hogwarts to those who ask for it.
Re[7]: Синхронизация коллекции !!!
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 21.02.07 08:57
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Здравствуйте, _FRED_, Вы писали:


_FR>>Это не синхронизация, а х… б… ё… Ясно?


А> Ясен пень это не синхронизация, это возможность для переключения потоков, что-бы посмотреть как они синхронизируются


_FR>>Потому что есть разница в том, что бы залочить весь список на время всех операций и в том, что бы лочить список на время каждой операции. Чуешь? Во втором случае какие-то (из других потоков) операции могут пролезть между "твоими" (из текущего потока) операциями. Из-за этого-то твоя логика и не выполняется.


А> Имеешь в виду, что другие потоки могут выполнить свои операции между вызовами IndexOf(), RemoveAt() и Insert()? Тоесть планировщик задач ОС может заставить переключиться потоки в момент когда текущий поток вышел из метода и его lock()-блока? Но тогда получается, что "синхронизация оберткой", прокатывает только в том случае если все потоки юзают ОДИН метод? Т.к. если используются два метода Коллекции, все равно между ними может произойти переключение задач?


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

_FR>>Такие вещи говорят исключительно о не хороших сторонах автора


А> Ну хорошо тогда покажи мне как еще проще заставить потоки переключаться? Это-же просто тестовый пример, а не коммерческое приложение


Есть очень много способов — читайте о примитивах синхронизации. Например, monitor.Wait и Monitor.Pulse...

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


А> Ну опять-же, это утвержедние имеет смысл, если все потоки пользуются ЕДИНСТВЕННЫМ методом для поиска в Коллекции.


Опять же неверное утверждение.

А> А кстати, метод Add() вообще синхронизируется?\


См. выше — открывайте рефлектором и смотрите.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[8]: Синхронизация коллекции !!!
От: Аноним  
Дата: 21.02.07 09:12
Оценка:
Здравствуйте, pt4h, Вы писали:

P>Большинство методов синхронизированной коллекции используют один и тот же объект синхронизации, а это значит, что потоки будут синхронизироваться при использовании любого из этих методов.


Как уже было написано выше, потоки будут синхронизированы, если используется ОДИН метод в потоке. Т.к. если их ДВА(или больше), то никто(без внешнего lock()-блока) не сможет гарантировать, что переключение задач не произойдет между вызовами этих двух методов ! Обьект синхронизации один, только синхронизация работает только внутри метода!

P>Есть очень много способов — читайте о примитивах синхронизации. Например, monitor.Wait и Monitor.Pulse...


Читайте по губам. ЭТО ПРОСТО ТЕСТ, ИСПОЛЬЗОВАЛ Sleep, ПОТОМУ ЧТО ТАК ПРОЩЕ ДОБИТЬСЯ ПЕРЕКЛЮЧЕНИЯ ЗАДАЧ.

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


А>> Ну опять-же, это утвержедние имеет смысл, если все потоки пользуются ЕДИНСТВЕННЫМ методом для поиска в Коллекции.


P>Опять же неверное утверждение.


Ну приведи мне пример, когда используются несколько методов(не заключенных в lock()-блок) синхронизированной Коллекции, и несколько потоков взаимодействующих с ними. Да так, что-бы их поведение можно было предсказать(нельзя использовать средства синхронизации, кроме "обертки" ArrayList.Synchronized())!
Re[9]: Синхронизация коллекции !!!
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 21.02.07 09:30
Оценка:
Здравствуйте, <Аноним>, Вы писали:

<skipped>

А> Ну приведи мне пример, когда используются несколько методов(не заключенных в lock()-блок) синхронизированной Коллекции, и несколько потоков взаимодействующих с ними. Да так, что-бы их поведение можно было предсказать(нельзя использовать средства синхронизации, кроме "обертки" ArrayList.Synchronized())!


Оба потока вызывают метод Add у синхронизированной коллеции — поведение предсказуемое, так как потоки не разрушат внутреннее состоянии коллекции.

Синхронизованная коллекция необходима, чтобы не разрушить внутренне состояние и не является примитивом синхронизации. Смиритесь с этим и пользуйтесь вменяемыми способами синхронизации потоков. Дальнейшее обсуждение не имеет смысла.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: Синхронизация коллекции !!!
От: Аноним  
Дата: 21.02.07 21:20
Оценка:
Здравствуйте, pt4h, Вы писали:

P>Оба потока вызывают метод Add у синхронизированной коллеции — поведение предсказуемое, так как потоки не разрушат внутреннее состоянии коллекции.


Да но они вызывают ОДИН метод. И в ЕГО пределах синхронизированы.

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


Последняя фраза звучит как вердикт Но похоже ты не понял, что я имею ввиду. Если:

  ...
  Collection.IndexOf(value);

  //Ну ни кто не гарантирует, что когда Поток_1 здесь остановиться, Поток_2 не влезет в один из этих методов.

  Collection.Add(value);
  ...


Вот я и говорю, синхронизируются только на уровне методов. Просто я предполагал, что использовать обертку все равно что сделать так:

  ...
  lock(SyncObj)
  {
     Collection.IndexOf(value);

     //Ну ни кто не гарантирует, что когда Поток_1 здесь остановиться, Поток_2 не влезет в один из этих методов.

     Collection.Add(value);
  }
  ...


И ошибался...
Re[11]: Синхронизация коллекции !!!
От: pt4h Беларусь http://dzmitryhuba.blogspot.com/
Дата: 22.02.07 07:44
Оценка:
Здравствуйте, <Аноним>, Вы писали:


А> И ошибался...


Мы все ошибаемся
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.