В lock путаются очередь
Atom Ответить
04.05.2013


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

Code

        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);
            }
        }


Результат
Code
Отправка 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).


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

Теги:


Спасибо:




11 Ответов
VassilSanych

Фотография
Дата: 05.05.2013
Ответить


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

casper-ss

Фотография
Дата: 22.06.2013
Ответить


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

yar1k0v

Фотография
Дата: 23.06.2013
Ответить


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

Code

new System.Threading.Tasks.Task(() => { }).Start();
или
new System.Threading.Tasks.TaskFactory().StartNew(() => { }).Start();
Спасибо:

yar1k0v

Фотография
Дата: 23.06.2013
Ответить


Quote:

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);
}
}


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

MenDel

Фотография
Дата: 23.06.2013
Ответить


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

Code
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(); 
Автор топика
Спасибо:

MenDel

Фотография
Дата: 23.06.2013
Ответить


yar1k0v Go to
Quote:

Code
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);
    }
}



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



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

yar1k0v

Фотография
Дата: 24.06.2013
Ответить


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


Вот пример:
Code

        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 (0)
Спасибо:

MenDel

Фотография
Дата: 24.06.2013
Ответить


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


Вот пример:

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

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




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

Code
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 больше

Есть еще мысли?
Автор топика
Спасибо:

yar1k0v

Фотография
Дата: 24.06.2013
Ответить


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

П.С.

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

MenDel

Фотография
Дата: 25.06.2013
Ответить


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

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

yar1k0v

Фотография
Дата: 25.06.2013
Ответить


Попробуй AutoResetEvent... Пример использования есть в примере S# QUIK Console, что то такое... Там как раз то что нужно)
Спасибо:


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

loading
clippy