В lock путаются очередь

В lock путаются очередь
Atom
5/4/2013
MenDel


Только сейчас заметил, что в lock путается очередь. Вот простой код для проверки


        private Thread t;
        private int i = 0;
        private readonly SyncObject _syncLock = new SyncObject();
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            i++;
            t = new Thread(SSS);
            t.Start(i);
        }

        private void SSS(object ii)
        {
            lock (_syncLock)
            {
                Debug.WriteLine("Отправка " + ii);
                Thread.Sleep(3000);
                Debug.WriteLine("Получение " + ii);
            }
        }

Результат

Отправка 1
Получение 1
Поток '<Без имени>' (0x1c98) завершился с кодом 0 (0x0).
Отправка 10
Получение 10
Поток '<Без имени>' (0x1b28) завершился с кодом 0 (0x0).
Отправка 9
Получение 9
Поток '<Без имени>' (0x2350) завершился с кодом 0 (0x0).
Отправка 7
Получение 7
Поток '<Без имени>' (0x1d68) завершился с кодом 0 (0x0).
Отправка 8
Получение 8
Поток '<Без имени>' (0x2338) завершился с кодом 0 (0x0).
Отправка 6
Получение 6
Поток '<Без имени>' (0x20c4) завершился с кодом 0 (0x0).
Отправка 5
Получение 5
Поток '<Без имени>' (0x240) завершился с кодом 0 (0x0).
Отправка 4
Получение 4
Поток '<Без имени>' (0x1e8c) завершился с кодом 0 (0x0).
Отправка 2
Получение 2
Поток '<Без имени>' (0x470) завершился с кодом 0 (0x0).
Отправка 3
Получение 3
Поток '<Без имени>' (0x1f20) завершился с кодом 0 (0x0).

Мне кажется такого же не должно быть. Или я где то не прав?


Tags:


Thanks:


1 2  >
VassilSanych

Avatar
Date: 5/5/2013
Reply


Создание потока без пула - штука тяжёлая. Скорее всего это не lock путается, а то что приходит в него. PS Попробуйте Task.Run(...)

Thanks:

casper-ss

Avatar
Date: 6/22/2013
Reply


А можно по подробнее про Task.Run...если не сложно...что это и с чем едят?первый раз увидел просто...

Thanks:

yar1k0v

Avatar
Date: 6/23/2013
Reply


Task - задача для выполнения в фоновом потоке


new System.Threading.Tasks.Task(() => { }).Start();
или
new System.Threading.Tasks.TaskFactory().StartNew(() => { }).Start();

Thanks:

yar1k0v

Avatar
Date: 6/23/2013
Reply


private Thread t; private int i = 0; private readonly SyncObject _syncLock = new SyncObject(); private void button1_Click(object sender, RoutedEventArgs e) { i++; t = new Thread(SSS); t.Start(i); }

private void SSS(object ii) { lock (_syncLock) { Debug.WriteLine("Отправка " + ii); Thread.Sleep(3000); Debug.WriteLine("Получение " + ii); } }

суть кода не понятна... вообще на переменную итерации в данном случае нужно накладывать лок, если вы тестили поочередность исполнения.

Thanks:

MenDel

Avatar
Date: 6/23/2013
Reply


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

BlockingCollection<string[]> _queue = new BlockingCollection<string[]>(new ConcurrentQueue<string[]>());
Thread bt = new Thread(() =>
                {
                    while (true)
                    {
                        // Thread.Sleep(1000); Можно добавить
                        if (_queue.Count == 0) continue;
                        var val = _queue.Take();
                        SmsSend(val); // Метод которому посылается val
                    }
                }) { Name = "bt", IsBackground = true };
backThread.Start(); 
Thanks:

MenDel

Avatar
Date: 6/23/2013
Reply


...

суть кода не понятна... вообще на переменную итерации в данном случае нужно накладывать лок, если вы тестили поочередность исполнения.

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

Thanks:

yar1k0v

Avatar
Date: 6/24/2013
Reply


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

Вот пример:


        int i = 0;
        static object locker = new object();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Start_Click(object sender, RoutedEventArgs e)
        {
            lock (locker) { i++; }
            new System.Threading.Thread(() =>
            {
                lock (locker)
                {
                    this.Dispatcher.BeginInvoke((Action)delegate()
                    {
                        Text.Text = "Started " + i.ToString();
                    });
                    System.Threading.Thread.Sleep(2000);
                    this.Dispatcher.BeginInvoke((Action)delegate() 
                    {
                        Text.Text += Environment.NewLine;
                        Text.Text += "Finished " + i.ToString();
                    });
                }  
            }).Start();
        }

В данном примере ничего не путается.

Почему lock на переменную итерации нельзя накладывать? Расскажите пожалуйста, буду знать. Спасибо!

ThreadsWorks.zip 53 KB (593)
Thanks:

MenDel

Avatar
Date: 6/24/2013
Reply


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

Вот пример:


        int i = 0;
        static object locker = new object();

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Start_Click(object sender, RoutedEventArgs e)
        {
            lock (locker) { i++; }
            new System.Threading.Thread(() =>
            {
                lock (locker)
                {
                    this.Dispatcher.BeginInvoke((Action)delegate()
                    {
                        Text.Text = "Started " + i.ToString();
                    });
                    System.Threading.Thread.Sleep(2000);
                    this.Dispatcher.BeginInvoke((Action)delegate() 
                    {
                        Text.Text += Environment.NewLine;
                        Text.Text += "Finished " + i.ToString();
                    });
                }  
            }).Start();
        }

В данном примере ничего не путается.

Почему lock на переменную итерации нельзя накладывать? Расскажите пожалуйста, буду знать. Спасибо!

Если усыпить поток не на 2, а на 5 секунд вот, что получилось (я нажал на кнопку 15 раз) Результаты вывел не на форму, а в дебаг

Started 1
Поток '<Без имени>' (0x2bb4) завершился с кодом 0 (0x0).
Finished 2
Started 2
Поток '<Без имени>' (0x2a1c) завершился с кодом 0 (0x0).
Finished 3
Started 3
Поток '<Без имени>' (0x1830) завершился с кодом 0 (0x0).
Поток '<Без имени>' (0x1fe4) завершился с кодом 0 (0x0).
Finished 4
Started 4
Поток '<Без имени>' (0x14ac) завершился с кодом 0 (0x0).
Finished 5
Started 5
Поток '<Без имени>' (0x2934) завершился с кодом 0 (0x0).
Finished 5
  1. В результате сработало только 5 раз из 15
  2. Форма повисла
  3. Не понял по какой причине в Finished число идет на 1 больше

Есть еще мысли?

Thanks:

yar1k0v

Avatar
Date: 6/24/2013
Reply


Прости, у меня такой проблемы не возникало. И сам пример, даже после нажатия 15 раз нормально работает. Может скажешь какова суть эксперимента? Возможно я смогу помочь по более конкретной задаче? Зависать может из за нехватки ресурсов, хз... Я не знаю как устроен метод Sleep(), я лишь знаю что он делает. Но видимо в нем причина зависания. Возможно пока он слипит текущий поток, запускается следующий. Ну и из за этого неполадки.

П.С.

Для меня например до сих пор загадка принцип работы new Random().Next(int min, int max) =) а именно почему при одновременном вызове нескольких таких методов, возвращаемые значения идентичны?

Thanks:

MenDel

Avatar
Date: 6/25/2013
Reply


Про Random мне тоже интересно почему так.

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

Thanks:
1 2  >

Attach files by dragging & dropping, , or pasting from the clipboard.

loading
clippy