none
Подскажите способ для синхронизации потоков. RRS feed

  • Вопрос

  • Дана структура данных и три операции в ней Add, Remove, Read :

    1. Read

    Другие потоки могут выполнять Read

    Другие потоки не могут выполнять Add, Remove

    2. Add.

    Другие потоки не могут выполнять Add, Remove, Read

    3. Remove. 

    Другие потоки не могут выполнять Add, Remove, Read

    С помощью оператора lock это нельзя выполнять, что еще можно посмотреть?

    13 февраля 2012 г. 15:18

Ответы

Все ответы

  • Может подойдёт одна из коллекций System.Collections.Concurrent Namespace?
    13 февраля 2012 г. 15:35
  • Нет не подойдет. Вопрос не о коллекциях а о способе синхронизации.
    • Изменено Max Charp 13 февраля 2012 г. 19:07
    13 февраля 2012 г. 19:06
  • Здравствуйте.

    А чем lock не подходит?

    Выполняйте lock внутри операции Add и Remove на всю операцию. А в Read просто проверяйте lock, т.е. пустой блок {}. Таким образом если выполняется Add или Remove, то чтение будет ожидать их окончания.

    Также посмотрите на Double checked locking, возможно этот шаблон вам подойдет больше.


    Для связи [mail]


    13 февраля 2012 г. 21:49
  • >>А в Read просто проверяйте lock, т.е. пустой блок {}

    Я немного вас не понял, что это значит 

        class Any
        {
            void Read()
            {
                // Что должно быть здесь?
                {
                    // ...
                }
            }
    
            void Add()
            {
                lock (this)
                {
                    // ...
                }
            }
    
            void Remove()
            {
                lock (this)
                {
                    // ...
                }
            }
        }


    14 февраля 2012 г. 0:57
  • > Другие потоки могут выполнять Read Другие потоки не могут выполнять Add, Remove [...] С помощью оператора lock это нельзя выполнять, что еще можно посмотреть?

     
    см. ReaderWriterLock и ReaderWriterLockSlim  
     

    • Изменено Malobukv 14 февраля 2012 г. 1:07
    • Помечено в качестве ответа Max Charp 14 февраля 2012 г. 3:34
    14 февраля 2012 г. 1:06
  • Any - Вариант предложенный Abolmasov Dmitry

    Any2 -  Вариант предложенный Malobukv (рабочий вариант :)

    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    namespace ThreadTest
    {
        class Program
        {
            static Any Any;
            //static Any2 Any;
    
            static void Main(string[] args)
            {
                Any = new Any();
                //Any = new Any2();
    
                StartAnyTest();
    
                Console.ReadLine();
            }
    
            static void StartAnyTest()
            {
                var ts_add      = new ThreadStart(AddThread);
                var ts_remove   = new ThreadStart(RemoveThread);
                var ts_read     = new ThreadStart(ReadThread);
                
                new Thread(ts_add).Start();
                new Thread(ts_add).Start();
                new Thread(ts_remove).Start();
                new Thread(ts_remove).Start();
                new Thread(ts_read).Start();
                new Thread(ts_read).Start();
                new Thread(ts_read).Start();
                new Thread(ts_read).Start();
                new Thread(ts_read).Start();
            }
    
            static void AddThread()
            {
                while (true)
                {
                    if (Any.Count < 500)
                    {
                        Any.Add();
                    }
                }
            }
    
            static void RemoveThread()
            {
                while (true)
                {
                    if (Any.Count > 300)
                    {
                        Any.Remove();
                    }
                }
            }
    
            static void ReadThread()
            {
                while (true)
                {
                    Any.Read();
                }
            }
        }
    
        class Any
        {
            List<int> list = new List<int>();
    
            public void Read()
            {
                lock(this)
                {
                    // ...
                }
    
                var count = list.Count - 1;
    
                try
                {
                    for (int i = 0; i < count; ++i)
                    {
                        var val = list[i];
    
                        if (val > 1000)
                        {
                            Console.WriteLine("Overhead");
                        }
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(count + "\\" + list.Count);
                    Console.WriteLine(exp.Message);
                }
            }
    
            public void Add()
            {
                lock (this)
                {
                    for (int i = 0; i < 50; i++)
                    {
                        list.Add(i);
                    }
                }
            }
    
            public void Remove()
            {
                lock (this)
                {
                    for (int i = 0; i < 50; i++)
                    {
                        list.RemoveAt(list.Count-1);
                    }
                }
            }
    
            public int Count { get { return list.Count; }}
        }
    
        class Any2
        {
            List<int> list = new List<int>();
    
            //static SpinLock spinlock = new SpinLock();
            ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
    
            public void Read()
            {
                Locker.EnterReadLock();
    
                Console.WriteLine(Locker.CurrentReadCount);
    
                try
                {
                    var count = list.Count - 1;
    
                    try
                    {
                        for (int i = 0; i < count; ++i)
                        {
                            var val = list[i];
    
                            if (val > 1000)
                            {
                                Console.WriteLine("Overhead");
                            }
                        }
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine(count + "\\" + list.Count);
                        Console.WriteLine(exp.Message);
                    }
                }
                finally
                {
                    Locker.ExitReadLock();
                }
            }
    
            public void Add()
            {
                Locker.EnterWriteLock();
    
                try
                {
                    for (int i = 0; i < 50; i++)
                    {
                        list.Add(i);
                    }
                }
                finally
                {
                    Locker.ExitWriteLock();
                }
            }
    
            public void Remove()
            {
                Locker.EnterWriteLock();
    
                try
                {
                    for (int i = 0; i < 50; i++)
                    {
                        list.RemoveAt(list.Count - 1);
                    }
                }
                finally
                {
                    Locker.ExitWriteLock();
                }
            }
    
            public int Count { get { return list.Count; }}
        }
    }
    


    14 февраля 2012 г. 3:40
  • Вы случайно не знаете в ReaderWriterLockSlim  используется механизм lock или spinLock ? 
    14 февраля 2012 г. 3:42
  • > в ReaderWriterLockSlim используется механизм lock или spinLock ?
     
     
    нет (Monitor и SpinLock не используются)

    p.s.
    на реализацию класса можно посмотреть с помощь браузера сборок : ILSpy или Reflector 
     
     

    • Изменено Malobukv 15 февраля 2012 г. 10:21
    15 февраля 2012 г. 10:14