Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.96/162: Рейтинг темы: голосов - 162, средняя оценка - 4.96
98 / 81 / 16
Регистрация: 14.01.2011
Сообщений: 438

Блокировка потока методом Lock

07.12.2011, 11:54. Показов 33875. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем добрый день. Что с потоками никак толком не разберусь. Метод lock как производит блокировку не совсем понятно. Вот цитата из книги:
XML
1
2
3
4
 "Инструкция lock гарантирует, что указанный блок кода, защищенный блоки-
ровкой для данного объекта, может быть использован только потоком, который полу-
чает эту блокировку. Все другие потоки остаются заблокированными до тех пор, пока
блокировка не будет снята. А снята она будет лишь при выходе из этого блока."
Не совсем понятно.Если поток не обращается к методу,он тоже будет заблокирован,пока другой поток не завершит работу?Допустим вот код:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class MyMeths
    {
        int summa;
        int multiply;
        public int SumArr(int[] nums)
        {
            lock (this)
            {
                summa = 0;
                for (int i = 0; i < nums.Length; i++)
                {
                    Console.WriteLine("Промежуточная сумма для потока <" +Thread.CurrentThread.Name+ "> равна :"+summa);
                    summa += nums[i];
                }
                return summa;
            }
        }
 
        public int MultiplyArr (int[] nums)
        {
            lock(this) 
            {
                multiply = 1;
                for (int i = 1; i < nums.Length+1; i++)
                {
                    Console.WriteLine("Промежуточное произведение для потока <" + Thread.CurrentThread.Name + "> равно :" + multiply);
                    multiply *= i;
                }
                return multiply;
            }
        }
    }
 
    class MyThread
    {
        int[] a;
        int answer; //сумма
        int mylt; //произведение
        public Thread thrd;
        MyMeths mymet = new MyMeths();
 
        public MyThread(string name,int[] nums)
        {
            thrd = new Thread(new ThreadStart(Run));
            thrd.Name = name;
            a = nums;
            thrd.Start();
        }
 
        void Run()
        {
            Console.WriteLine("<"+thrd.Name+"> стартовал");
            if (thrd.Name=="Сумма") 
            {
                answer = mymet.SumArr(a);
                Console.WriteLine("Сумма для потока <" + thrd.Name + "> равна " + answer);
            }
            if (thrd.Name == "Произведение") 
            {
                mylt = mymet.MultiplyArr(a);
                Console.WriteLine("Произведние для потока <"+thrd.Name+"> равно "+mylt);
            }
            Console.WriteLine("<"+thrd.Name + "> завершён");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            int[] b = { 1, 2, 3, 4, 5 };
            MyThread mt1 = new MyThread("Сумма",b);
            MyThread mt2 = new MyThread("Произведение", b);
 
            mt1.thrd.Join();
            mt2.thrd.Join();
 
            Console.ReadKey();
        }
    }
}
Есть 2 метода,определённые в одном классе.Один суммирует массив,другой произведение вычисляет. Оба заблокированы.Делегат принимает метод Run в обоих созданных дочерних потоках(в Main()).В этом методе идёт разделение по именам потоков.Если одно имя - выполняем один метод,если другое,то другой метод. Т.е. если lock блокирует часть кода,которую использует поток (например №1) вызывая метод №1,то поток №2 не может разве обратиться к другому методу? Т.е. lock блокирует остальные потоки ,вне зависимости какую часть кода они пытаются использовать, пока не завершит выполнение.Или же lock блокирует остальные потоки именно к отдельной части кода? Да и вообще результаты программы разные. По идее если lock блокирует другие потоки(не зависимо к какой часть кода они обращаются),то сначала должен полностью выполниться первый поток,потом второй. А если lock блокирует только поток,вызвавший именно этот метод,то потоки должны выполняться о очереди,распределяя время ЦП. Направьте на истинный путь,запутался уже. Да и вообще результаты программы разные иногда. Т.е.то по очереди потоки выполняются,то один немного залезает во время выполнения другого.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
07.12.2011, 11:54
Ответы с готовыми решениями:

Рекурсивная блокировка (C#, lock()
Привет, подскажите, как это работает: internal class Program { private static Object syncObject = new Object(); private...

Как создать три потока с одним методом
Не могу создать 3 потока и запустить их. Суть проги такая. В ТекстБокс1 и ТекстБокс2 вводятся данные, если эти данные числа, то они...

Как усыплять дочерний поток реализуя управление элементами из главного потока методом Invoke
как управлять элементами из главного потока в дочернем? Если напишите методом Invoke, то объясните тогда - как заставять в определённых...

6
185 / 185 / 53
Регистрация: 10.04.2009
Сообщений: 491
07.12.2011, 12:31
этот кусок
C#
1
2
3
4
5
6
7
8
9
10
            lock(this) 
            {
                multiply = 1;
                for (int i = 1; i < nums.Length+1; i++)
                {
                    Console.WriteLine("Промежуточное произведение для потока <" + Thread.CurrentThread.Name + "> равно :" + multiply);
                    multiply *= i;
                }
                return multiply;
            }
lock(this) - устанавливает блокиратор на этот экземпляр через this, вот и 2 lock(this) будут выполнятся по очереди, то есть если 2 потока выполняют 2 метода, то никакой параллельности не будет ....
другой вариант(более правильный):
для метода суммирования
C#
1
2
3
4
object lockerForAdd = new object();
lock(lockerForAdd ){
//do your math
}
для умножения
C#
1
2
3
4
object lockerForMult = new object();
lock(lockerForMult ){
//do you math
}
так добились что суммирование и умножение 2 потоками для 1 экземпляра может выполнятся параллельно
2
98 / 81 / 16
Регистрация: 14.01.2011
Сообщений: 438
07.12.2011, 12:44  [ТС]
Спасибо,но результат тот же.Скрин выполнения программы использую первый мой код.Потом изменил как Вы посоветовали,результат тот же.
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class MyMeths
    {
        int summa;
        int multiply;
        public int SumArr(int[] nums)
        {
            object aa = new object();
            lock (aa)
            {
                summa = 0;
                for (int i = 0; i < nums.Length; i++)
                {
                    Console.WriteLine("Промежуточная сумма для потока <" +Thread.CurrentThread.Name+ "> равна :"+summa);
                    summa += nums[i];
                }
                return summa;
            }
        }
 
        public int MultiplyArr (int[] nums)
        {
            object bb = new object();
            lock(bb) 
            {
                multiply = 1;
                for (int i = 1; i < nums.Length+1; i++)
                {
                    Console.WriteLine("Промежуточное произведение для потока <" + Thread.CurrentThread.Name + "> равно :" + multiply);
                    multiply *= i;
                }
                return multiply;
            }
        }
    }
 
    class MyThread
    {
        int[] a;
        int answer; //сумма
        int mylt; //произведение
        public Thread thrd;
        MyMeths mymet = new MyMeths();
 
        public MyThread(string name,int[] nums)
        {
            thrd = new Thread(new ThreadStart(Run));
            thrd.Name = name;
            a = nums;
            thrd.Start();
        }
 
        void Run()
        {
            Console.WriteLine("<"+thrd.Name+"> стартовал");
            if (thrd.Name=="Сумма") 
            {
                answer = mymet.SumArr(a);
                Console.WriteLine("Сумма для потока <" + thrd.Name + "> равна " + answer);
            }
            if (thrd.Name == "Произведение") 
            {
                mylt = mymet.MultiplyArr(a);
                Console.WriteLine("Произведние для потока <"+thrd.Name+"> равно "+mylt);
            }
            Console.WriteLine("<"+thrd.Name + "> завершён");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            int[] b = { 1, 2, 3, 4, 5 };
            MyThread mt1 = new MyThread("Сумма",b);
            MyThread mt2 = new MyThread("Произведение", b);
 
            mt1.thrd.Join();
            mt2.thrd.Join();
 
            Console.ReadKey();
        }
    }
}
Миниатюры
Блокировка потока методом Lock  
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
07.12.2011, 12:57
Цитата Сообщение от NowMatrix Посмотреть сообщение
C#
1
2
3
4
5
public int SumArr(int[] nums)
 {
 object aa = new object();
 lock (aa)
 {
Это равносильно тому, вообще убрать код синхронизации, так как вы замыкаетесь на локальном объекте, невидимом другим потокам по определению. В результате никакого замыкания не будет.

Вообще я не совсем понял какое поведение вы ожидаете. Если напишете что именно должно происходить, то я смогу сказать в чем проблема.
1
Заблокирован
07.12.2011, 12:57
Попробую обьяснить.

Потоки друг друга не блокируют, они блокируют участок кода для работы с ним. Блокированный код может одновременно исполняться только одним потоком.
Если поток доходит до участка кода
C#
1
2
3
4
            lock (locker1)
            {
                //операторы
            }
проверяется, исполняется ли этот участок кода другим потоком, если да - наш поток ожидает, пока другой поток не закончит с ним работать, если нет - поток блокирует этот участок кода чтоб другие потоки не мешали и работает с ним.

Если используете для блокировок разных участков кода отдельные обьекты locker1, locker2,... , то эти блокировки никак не взаимосвязаны. Т.е. если один поток заблокировал lock (locker1){...}, другой поток не может работать только с этим учаском кода, пока тот не освободиться.

Примерно так.
------------------

Пока писал, уже ответили.
В вашем случае блокировки лишние, результат будет примерно одинаков.
Берете одни и те же данные, их не изменяете, а результаты записываете в разные переменные.

Блокируются "критические" участки кода.

Например, запись в лог-файл. Если один поток хочет записать в файл в то время как другой уже пишет в этот файл, приложение вылетает с ошибкой "файл занят другим приложением". Для того чтобы в файл было записано полностью все что нужно и без сбоев и сделали этот механизм.

Попробуйте выводить не на консоль(она потокобезопасная), а в один и тот же файл с блокировкой и без. И циклы побольше.
1
185 / 185 / 53
Регистрация: 10.04.2009
Сообщений: 491
07.12.2011, 13:14
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 public int SumArr(int[] nums)
        {
//этого объекта не должно тут быть,  он должен быть в глобальным для класса
            object aa = new object();
            lock (aa)
            {
                summa = 0;
                for (int i = 0; i < nums.Length; i++)
                {
                    Console.WriteLine("Промежуточная сумма для потока <" +Thread.CurrentThread.Name+ "> равна :"+summa);
                    summa += nums[i];
                }
                return summa;
            }
        }
так же для наглядности параллелизма добавьте задержку, Thread.Sleep(100);

Добавлено через 3 минуты
хотя у Вас ошибка на ошибке

Добавлено через 5 минут
вот Вам пример действительно параллельного выполнения
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
class MyMeths
    {
        int summa;
        int multiply;
        object lockerAdd = new object();
        object lockerMult = new object();
        public int SumArr(int[] nums)
        {
            lock (lockerAdd)
            {
                summa = 0;
                for (int i = 0; i < nums.Length; i++)
                {
                    Console.WriteLine("Промежуточная сумма для потока <" + Thread.CurrentThread.Name + "> равна :" + summa);
                    summa += nums[i];
                    Thread.Sleep(500);
                }
                return summa;
            }
        }
 
        public int MultiplyArr(int[] nums)
        {
            lock (lockerMult)
            {
                multiply = 1;
                for (int i = 1; i < nums.Length + 1; i++)
                {
                    Console.WriteLine("Промежуточное произведение для потока <" + Thread.CurrentThread.Name + "> равно :" + multiply);
                    multiply *= i;
                    Thread.Sleep(500);
                }
                return multiply;
            }
        }
    }
 
    class MyThread
    {
        int[] a;
        int answer; //сумма
        int mylt; //произведение
        public Thread thrd;
        MyMeths mymet = null;
 
        public MyThread(string name, int[] nums, MyMeths m)
        {
            thrd = new Thread(new ThreadStart(Run));
            thrd.Name = name;
            a = nums;
            mymet = m;
            thrd.Start();
        }
 
        void Run()
        {
            Console.WriteLine("<" + thrd.Name + "> стартовал");
            if (thrd.Name == "Сумма")
            {
                answer = mymet.SumArr(a);
                Console.WriteLine("Сумма для потока <" + thrd.Name + "> равна " + answer);
            }
            if (thrd.Name == "Произведение")
            {
                mylt = mymet.MultiplyArr(a);
                Console.WriteLine("Произведние для потока <" + thrd.Name + "> равно " + mylt);
            }
            Console.WriteLine("<" + thrd.Name + "> завершён");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            int[] b = { 1, 2, 3, 4, 5 };
            MyMeths m = new MyMeths();
            MyThread mt1 = new MyThread("Сумма", b, m);
            MyThread mt2 = new MyThread("Произведение", b, m);
 
            mt1.thrd.Join();
            mt2.thrd.Join();
 
            Console.ReadKey();
        }
    }
1
98 / 81 / 16
Регистрация: 14.01.2011
Сообщений: 438
07.12.2011, 13:39  [ТС]
Ладно,услышал кое что однозначное для себя,буду разбираться.Спасибо всем за отзывчивость и объяснения.

Добавлено через 11 минут
Ну да я объектами для lock намудрил,не подумал что потоки не увидят их. И я понял,когда используем Thread.Sleep() - то приостанавливаем поток,давая другому доступ. Точнее не доступ,а время успеть отобразить на экране слова по очереди. Я просто не использовал этого.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
07.12.2011, 13:39
Помогаю со студенческими работами здесь

блокировка таблицы (lock) - как найти причину?
Мне нужно из таблицы удалить строку. Делаю это с помощью инструкции T-SQL Delete, но запрос подвисает. Пытался просто просмотреть данные с...

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru