Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.89/9: Рейтинг темы: голосов - 9, средняя оценка - 4.89
214 / 148 / 48
Регистрация: 28.12.2016
Сообщений: 716
1

Lock не работает. Блокировать переменную мнопоточность

11.11.2018, 23:49. Показов 1768. Ответов 12
Метки нет (Все метки)

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private Counter counter = new Counter();
 
        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 10; i++)
                new Thread(Work).Start();
            
            Thread.Sleep(1000);
 
            //смотрим переменную counter. Она должна быть 10 000 000
            Console.WriteLine(counter.Value);//упс...
        }
        private void Work()
        {
            for (int i = 0; i < 1000000; i++)
            {
                counter.Value++;
            }
             
        }
    }
 
    class Counter
    {
        private int _value;
        private readonly object locker = new object();
        
        public int Value
        {
            get
            {
                lock (locker)
                    return _value;
            }
            set
            {
                lock (locker)
                    _value = value;
            }
        }
    }
Добавлено через 12 минут
Буду признателен, если поможете разобраться, мне просто мозг взрывает, я не понимаю почему блокировка не происходит, мы же используем 1 экземпляр класса Counter для всех потоков...
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.11.2018, 23:49
Ответы с готовыми решениями:

Клавиатура мигает всеми тремя индикаторами Caps Lock, Scroll Lock и Num Lock и соответственно не работает!
Здравствуйте парни и девушки! Столкнулся с такой проблемой! Имеется клавиатура Genius Ergomedia...

Как за блокировать(lock) Access базу?
Подскажите плз как заблокировать(lock) Access базу чтобы несколько запросов проходили, и между...

В каких ситуациях нужно блокировать поток методом lock?
Доброе время суток коллеги, подскажите новечку в каких ситуациях нужно блокировать топок методом...

Lock должен блокировать при заполнении - чтение и заполнение, а при чтении ничего
Доброго времени суток, проблема с блокировкой потоков lock. 1й поток в цикле заполняет коллекцию...

12
Эксперт .NET
4953 / 3387 / 1422
Регистрация: 09.05.2015
Сообщений: 8,283
11.11.2018, 23:54 2
У меня получается 10000000...

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    class Counter
    {
        private int _value;
        private readonly object locker = new object();
 
        public int Value
        {
            get
            {
                lock (locker)
                    return _value;
            }
            set
            {
                lock (locker)
                    _value = value;
            }
        }
    }
 
    class Program
    {
        private static Counter counter = new Counter();
 
        private static void Work()
        {
            for (int i = 0; i < 1000000; i++)
            {
                counter.Value++;
            }
        }
 
        static void Main(string[] args)
        {
            Thread[] threads = new Thread[10];
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i] = new Thread(Work);
                threads[i].Start();
                threads[i].Join();
            }
 
            //смотрим переменную counter. Она должна быть 10 000 000
            Console.WriteLine(counter.Value);//упс...
 
            Console.ReadLine();
        }
    }
0
Администратор
Эксперт .NET
13744 / 11136 / 4552
Регистрация: 17.03.2014
Сообщений: 22,473
Записей в блоге: 1
12.11.2018, 00:06 3
Defences, операции чтения/записи int и так атомарные. Защищать их lock-ом нет смысла. Защищать нужно арифметическую операцию целиком чтобы чтение+инкремент+запись были атомарной операцией. Плюс нужно дождаться что все потоки закончили работу, а не использовать Wait(1000) - нет никакой гарантии потоки успеют отработать за этой время.
0
214 / 148 / 48
Регистрация: 28.12.2016
Сообщений: 716
12.11.2018, 00:09  [ТС] 4
Someone007, ну у вас Join, поток новый не создается, пока старый не отработает, вы выполняете метод Work в 1 потоке, но разными потоками)

Добавлено через 1 минуту
OwenGlendower, окей, теперь мы ждем, смысл не меняется. нету блокировки...

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 private readonly Counter counter = new Counter();
        private void button11_Click(object sender, EventArgs e)
        {
            for (int y = 0; y < 10; y++)
            {
 
                Thread[] threads = new Thread[10];
                for (int i = 0; i < threads.Length; i++)
                {
                    threads[i] = new Thread(Work);
                    threads[i].Start();
                 
                }
                foreach (var t in threads)
                    t.Join();
                //смотрим переменную counter. Она должна быть 10 000 000
                Console.WriteLine(counter.Value); //упс...
            }
        }
        private void Work()
        {
            for (int i = 0; i < 1000000; i++)
            {
                counter.Value++;
            }
             
        }
 
class Counter
    {
        private int _value;
        private readonly object locker = new object();
 
        public int Value
        {
            get
            {
                lock (locker)
                    return _value;
            }
            set
            {
                lock (locker)
                    _value = value;
            }
        }
    }
0
Эксперт .NET
4953 / 3387 / 1422
Регистрация: 09.05.2015
Сообщений: 8,283
12.11.2018, 00:13 5
Цитата Сообщение от Defences Посмотреть сообщение
ну у вас Join, поток новый не создается, пока старый не отработает, вы выполняете метод Work в 1 потоке, но разными потоками
Ок, так все равно 10000000
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
    class Counter
    {
        private int _value;
 
        public int Value
        {
            get
            {
                return _value;
            }
            set
            {
                _value = value;
            }
        }
    }
 
    class Program
    {
        private static Counter counter = new Counter();
        private static readonly object locker = new object();
 
        private static void Work()
        {
            for (int i = 0; i < 1000000; i++)
            {
                lock (locker)
                    counter.Value++;
            }
        }
 
        static void Main(string[] args)
        {
            Thread[] threads = new Thread[10];
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i] = new Thread(Work);
                threads[i].Start();
            }
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }
 
            //смотрим переменную counter. Она должна быть 10 000 000
            Console.WriteLine(counter.Value);//упс...
        }
    }
1
214 / 148 / 48
Регистрация: 28.12.2016
Сообщений: 716
12.11.2018, 00:14  [ТС] 6
Если lock'ать вызов свойства в Work, то все гуд, но когда таких переменных куча, хочется не плодить не нужный код, но увы нельзя.

Просто если counter'ов будет 50, это 50 локов, 100 строк кода не нужных, когда мы могли написать всего 3 строки в классе Counter.

В общем как я понимаю это одна из многих загвоздок в шарпе и это никак не решить, вроде должен, но на самом деле не блокирует. Верно? Мне не стоит пытаться найти решение?
0
Эксперт .NET
15315 / 11609 / 3044
Регистрация: 17.09.2011
Сообщений: 19,432
12.11.2018, 00:18 7
Лучший ответ Сообщение было отмечено Defences как решение

Решение

Цитата Сообщение от Defences Посмотреть сообщение
вроде должен, но на самом деле не блокирует.
Все он блокирует, просто у вас синхронизация криво построена: вы сначала синхронизируете чтение, а потом отдельно синхронизируете запись. А между этими двумя операциями синхронизации нет.
Так что не в шарпе дело.
2
214 / 148 / 48
Регистрация: 28.12.2016
Сообщений: 716
12.11.2018, 00:20  [ТС] 8
Someone007, вы хитрый) Но это не lock, который в начале темы, это локать в методе)) Совсем разные вещи.

Именно мой код, у вас не будет работать) Я хочу знать в чем дело.

Добавлено через 1 минуту
kolorotur, то есть, в свойствах локать нельзя, да?

в get; set; нельзя ни в коем случае, я правильно понимаю?
0
Эксперт .NET
4953 / 3387 / 1422
Регистрация: 09.05.2015
Сообщений: 8,283
12.11.2018, 00:20 9
Цитата Сообщение от Defences Посмотреть сообщение
Я хочу знать в чем дело.
Выше написали в чем проблема, у вас отдельные локи на чтение и запись, а между ними может произойти что угодно...
0
Администратор
Эксперт .NET
13744 / 11136 / 4552
Регистрация: 17.03.2014
Сообщений: 22,473
Записей в блоге: 1
12.11.2018, 00:22 10
Defences, нужно всего лишь весь инкремент закрыть lock-ом.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Counter
{
    private int _value;
    private readonly object locker = new object();
    
    public int Value
    {
        get { return _value; }
    }
    public void Increment()
    {
        lock (locker)
        {
            _value++;
        }
    }
}
C#
1
2
3
4
5
6
7
private void Work()
{
    for (int i = 0; i < 1000000; i++)
    {
        counter.Increment();
    }
}
C#
1
2
3
4
5
6
7
8
9
10
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.Length; i++)
{
    threads[i] = new Thread(Work);
    threads[i].Start();
}
foreach (var t in threads) t.Join();
 
//смотрим переменную counter. Она должна быть 10 000 000
Console.WriteLine(counter.Value);
Добавлено через 1 минуту
Цитата Сообщение от Defences Посмотреть сообщение
то есть, в свойствах локать нельзя, да?
Можно. Просто в данном случае это не поможет потому что в перерыве между чтением и записью может вклинится другой поток.
1
Эксперт .NET
15315 / 11609 / 3044
Регистрация: 17.09.2011
Сообщений: 19,432
12.11.2018, 00:23 11
Цитата Сообщение от Defences Посмотреть сообщение
Я хочу знать в чем дело.
Причина названа во втором ответе.

Цитата Сообщение от Defences Посмотреть сообщение
то есть, в свойствах локать нельзя, да?
Можно.

Цитата Сообщение от Defences Посмотреть сообщение
в get; set; нельзя ни в коем случае, я правильно понимаю?
Можно.
1
214 / 148 / 48
Регистрация: 28.12.2016
Сообщений: 716
12.11.2018, 00:27  [ТС] 12
OwenGlendower, буду использовать Interlocker, блин хотелось через lock, удобно, но придется отказаться, ибо плодить ненужный код с блоком в методах не хочется. Я думал раз написать locker в колассе Counter и пусть он будет при создании экземпляра классов, но увы.

kolorotur, нельзя! Можно только другие объекты, но не переменную, которая привязана к свойству, по сути должно быть что-то около
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  public int Value
        {
         lock(locker)
          {
            get
            {
                    return _value;
            }
            set
            {
                    _value = value;
            }
          }
        }
А иначе будет не блока.
0
Эксперт .NET
15315 / 11609 / 3044
Регистрация: 17.09.2011
Сообщений: 19,432
12.11.2018, 00:31 13
Цитата Сообщение от Defences Посмотреть сообщение
нельзя!
Можно.

Цитата Сообщение от Defences Посмотреть сообщение
Можно только другие объекты, но не переменную, которая привязана к свойству
Можно что угодно.
Вы просто путаете инкремент и обращение к свойству.
Инкремент — это три разных операции, которые вы разбиваете на два отдельных замыкания.
Замыкания работают, просто вы их криво используете — вот и проблемы.

Цитата Сообщение от Defences Посмотреть сообщение
должно быть что-то около
Не должно.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.11.2018, 00:31

Вывести на экран в символическом виде состояние NUM LOCK, CAPS LOCK и SCROLL LOCK
Помогите решить задачку на турбо си Выводить на экран в символическом виде состояние NUM LOCK,...

Acer aspire 5552G-N974G64Mikk Проблема с Caps Lock, Num Lock, Scroll Lock
Вообщем у меня такая же проблемма https://www.cyberforum.ru/notebooks/thread552722.html ...

Работа с клавиатурой (клавиши num lock, caps lock, scroll lock)
определить состояние статуса клавиш &quot; num lock, caps lock,scroll lock &quot; с отображением и их...

Hola - как это работает, можно ли ее блокировать
Недавно столкнулся с такой штучкой, и задумался если наши дорогие коллеги запросто с помощью этого...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.