Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.93/14: Рейтинг темы: голосов - 14, средняя оценка - 4.93
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435

Потоки: синхронизированный доступ к стеку

21.02.2012, 22:24. Показов 2869. Ответов 21
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
в общем на картинке все нарисовано. Количество потоков нарисовал два, но на самом деле их может быть больше
Миниатюры
Потоки: синхронизированный доступ к стеку  
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
21.02.2012, 22:24
Ответы с готовыми решениями:

Перегрузка WebClient.GetRequest() и передача исключения вверх по стеку
Здравствуйте. Я расширил WebClient, чтобы пользоваться Cookies и некоторыми другими вещами. //CookieAwareWebClient.cs using System; ...

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

Потоки и доступ к элементам из них
Делаю приложение для получения некоторой информации из ВК средствами браузера awesomium, ибо встроенный в C# браузер вк не воспринимает. ...

21
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 01:03
В чем вопрос-то заключается?
Если нужен синхронизированный доступ к стеку, используйте BlockingCollection.
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 01:17  [ТС]
Под стеком я имел в виду простейший массив List
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 10:25
Тогда используйте обычную синхронизацию через lock:
C#
1
2
3
4
5
6
7
8
9
10
11
12
object locker = new object();
List<Something> list = new List<Something>();
 
void MethodThatRunsInThread()
{
   while (true)
   {
      lock (locker) 
         if (list.Count > 0) list.RemoveAt(0);         
      Thread.Sleep(500);
   }
}
Конечно, если вам надо реализовать блокирующуюся коллекцию, то лучше спин-лок не использовать, а воспользоваться уведомлениями.
Но для начала пойдет и так.
1
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 12:29  [ТС]
C#
1
2
3
4
5
6
7
 for (int i = 1; i < numericUpDown1.Value; i++)
                {
 
                    Thread thread = new Thread(new ParameterizedThreadStart(axixa));
                    thread.Start(i);
 
                }
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 private void axixa()
{
 lock (lockThis)
                {
                    for (int j = 1; j < Convert.ToInt32(textBox1.Text); j++)
                    {
 
                        GetEasylabViews("http:/xxx/search/page" + j");
                        Invoke(new MethodInvoker(() =>
                        {
                            label3.Text = j.ToString();
                        }));
 
                    }
                }
}
Создаю 10 потоков. Когда цикл доходит почти до конца потоки начинают один и тот же цикл выполнять..
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 12:44
Я не совсем понимаю что делает ваш код (точнее, не знаю что происходит в методе GetEasylabViews), но уже вижу проблему: вы замыкаете весь цикл. Зачем?
В результате у вас все потоки будут работать по порядку: пока один работает, другие ждут его завершения.
Старайтесь максимально минимизировать время, затрачиваемое на обработку критической зоны. То есть замыкайте только ту часть кода, где непосредственно происходит доступ к общему ресурсу.
Если в вашем случае общий ресурс - список чего-то, то замыкайте только ту часть кода, где происходит обращение к его свойствам или методам.
Чем меньше критическая зона, тем производительнее многопоточное приложение.
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 12:52  [ТС]
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
 private void GetEasylabViews(string URL)
        {
            string url = URL;
            string html = string.Empty;
            string pattern =("(.*)/profile");
 
            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(url);
            myRequest.AllowAutoRedirect = false;
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader sr = new StreamReader(myResponse.GetResponseStream(), Encoding.GetEncoding(1251));
            html = sr.ReadToEnd();
 
            var res = Regex.Matches(html, pattern);
 
            foreach (Match match in res)
            {
                var s = match.Value.Remove(0, 2);
                var len = s.Length - s.IndexOf("/");
                Invoke(new MethodInvoker(() =>
                {
                    textBox2.AppendText(s.Remove(s.IndexOf("/"), len));
                    textBox2.Text += Environment.NewLine;
                }));
                
                //MessageBox.Show(match.Value);
            }
 
            //  Console.WriteLine(match.Value);
        }
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 13:14
Я вообще не вижу никакого обращения к общим ресурсам, кроме записи в текстовое поле. Но запись все равно маршаллится в основной поток, так что синхронизировать ее не нужно.

И замените textBox2.Text += Environment.NewLine на textBox2.AppendText(Environment.NewLine) , а то сводите на нет использование этого метода в предыдущей строчке.
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 13:16  [ТС]
kolorotur, то есть многопоточность не имеет смысла?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 13:19
Многопоточность смысл имеет. Не имеет смысла синхронизация (блок lock), так как отсутствует обращение к общим ресурсам, а следовательно и повод для race condition (как оно по-русски правильно называется?).
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 13:50  [ТС]
kolorotur, а как быть с другой проблемой? Когда до конца цикла остается несколько позиций он начинает повторяться

Добавлено через 3 минуты
Когда убираю LOCK все потоки стремятся захватить данные))
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
22.02.2012, 16:39
C#
1
2
3
4
5
            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create(url);
            myRequest.AllowAutoRedirect = false;
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader sr = new StreamReader(myResponse.GetResponseStream(), Encoding.GetEncoding(1251));
            html = sr.ReadToEnd();
А разве не может быть такая ситуация: Предположим у нас 2 потока. Оба входят в метод GetEasylabViews первый поток доходит до html = sr.ReadToEnd(); но не выполняет эту строку, второй поток тоже проходит весь код (создавая новый StreamReader содержащий уже другие данные) до этой строки, в итоге оба потока потом поочереди считывают один и тот же последний запрос, то есть 2 потока обработают одни и теже данные. Разве нет? Если бы в потоки передавались 2 разных объекта, у которых есть этот метод, то у них и данные были бы разные, а так как оба потока заходят в метод одного объекта, то по идее должна возникнуть вышеописанная ситуация. Или нет (на 99.999...% уверен что так и есть)?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
22.02.2012, 16:45
Casper-SC, само обращение к sr из разных потоков не страшно, т.к. там разные объекты.

Проблема там в самой архитектуре: создается n потоков и каждый поток обрабатывает все адреса. То есть абсолютно каждый адрес будет обработан n количество раз.

Предполагаю, что таким образом ТС попытался реализовать паттерн Producer/Consumer, где n потоков обрабатывают x страниц, причем каждую страницу один раз.
Отсюда и (изначально) правильный вопрос про синхронизированный доступ к списку, но потом, видно, что-то пошло не так.
2
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
22.02.2012, 17:01
О ничего себе, я всё время себе всё не так представлял, просто была какая-то ошибка с запросами тоже помню, вот я так себе после неё всё поведение и начал представлять. Вот затестил, и вправду у каждого потока свои данные. Тестил через точки останова, поэтому особого смысла нету в методе GetEasylabViews.
Код
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
using System.IO; 
using System.Net;
using System.Text;
using System.Threading;
 
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Logic logic = new Logic();
            logic.RunTest();
        }
    }
 
    class Logic
    {
        Thread[] _threads;
        string[] _webSites;
 
        public Logic()
        {
            _webSites = new string[] { "http://www.google.com/", "http://www.yandex.ru/" };
            _threads = new Thread[_webSites.Length];
            for (int i = 0; i < _threads.Length; i++)
                _threads[i] = new Thread(new ParameterizedThreadStart(GetEasylabViews));
        }
 
        public void RunTest()
        {
            for (int i = 0; i < _threads.Length; i++)
                _threads[i].Start(_webSites[i]);
        }
 
        private void GetEasylabViews(object url)
        {
            string html = string.Empty;
            HttpWebRequest myRequest = (HttpWebRequest)HttpWebRequest.Create((string)url);
            myRequest.AllowAutoRedirect = false;
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            StreamReader sr = new StreamReader(myResponse.GetResponseStream(), Encoding.GetEncoding(1251));
            html = sr.ReadToEnd();
        }
    }
}
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 21:55  [ТС]
В общем как быть в моем случае?
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
22.02.2012, 21:59
Цитата Сообщение от Radzhab Посмотреть сообщение
В общем как быть в моем случае?
Сделать отдельный проект, воспроизвести в нём проблему, выложить сюда (или оригинал, не знаю что там у тебя и что ты можешь выложить,а что нет). Часто бывает, что проблемы в других участках кода, а не в тех что выкладывают.
0
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 22:28  [ТС]
Casper-SC, я использую ваш код. Но там количество потоков равняется количество данных в коллекции. То есть, если _websites штук 200 то и потоков будет 200..
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
22.02.2012, 22:35
Вот когда-то давно писал, может тут чуток переделаешь. Правда тут очереди, а не стек.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Threading;
using System.Collections;
using System.IO;
using System.Diagnostics;
 
namespace ConsApp_MultithreadedParser
{
    class Program
    {
        static void Main(string[] args)
        {
            string txtFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), "test.txt");
            string[] lines = System.IO.File.ReadAllLines(txtFile);
 
            Queue queue = new Queue(lines);
            Worker.DoWork(queue, 3);
 
            Console.ReadKey();
        }
    }
}
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
using System.Collections;
using System.Threading;
using System;
 
namespace ConsApp_MultithreadedParser
{
    public static class Worker
    {
        static object _locker;
        static object _lockerCount;
        static Queue _queue;
 
        /// <summary>
        /// 
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="MaxThreads">Максимальное количество работающих потоков</param>
        public static void DoWork(Queue queue, int MaxThreads)
        {
            _locker = new object();
            _lockerCount = new object();
            _queue = queue;
 
            //финальное кол-во работающих потоков. Если очередь меньше, чем кол-во потоков определённое в константе,
            //то создастся равное размеру очереди кол-во потоков.
            int finalQuantityThreads = _queue.Count < MaxThreads ? _queue.Count : MaxThreads;
 
            //создаём объекты работающие с логинами и паролями в кол-ве равном кол-ву рабочих потоков
            WebSiteParser[] webParsers = new WebSiteParser[finalQuantityThreads];
            Thread[] threads = new Thread[finalQuantityThreads];
 
            for (int i = 0; i < webParsers.Length; i++)
            {
                webParsers[i] = new WebSiteParser(); 
                threads[i] = new Thread(new ParameterizedThreadStart(delegate(object checkerObj)
                        {
                            WebSiteParser webParser = (WebSiteParser)checkerObj;
                            while (GetQueueCount() > 0)
                            {
                                string number = (string)GetObjectFromQueue();
                                if (number != null)
                                    webParser.Parse(new Uri(@"http://zzzzzzz.ru/listing.php/user?us_id=" + number), "<body>(.*?)</body>");
                            }
                        }));
                threads[i].Start(webParsers[i]);
            }
        }
 
        /// <summary>
        /// Получить объект из очереди потокобезопасным методом
        /// </summary>
        /// <returns></returns>
        private static object GetObjectFromQueue()
        {
            lock (_locker)
            {
                if (_queue.Count > 0)
                    return _queue.Dequeue();
                else
                    return null;
            }
        }
 
        /// <summary>
        /// Получить количество элементов в очереди потокобезопасным методом
        /// </summary>
        /// <returns></returns>
        private static int GetQueueCount()
        {
            lock (_lockerCount)
            {
                return _queue.Count;
            }
        }
    }
}
Добавлено через 1 минуту
Вот это помоему писал kolorotur когда-то давно, в той же теме, в которой я выкладывал код приведённый выше (если ошибаюсь, то сори, просто как бы я из лучших побуждений).
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
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
 
namespace ConsApp_Multithreading_UsingTasks
{
    class Program
    {
        // Блокирующая очередь. Сюда будут добавляться "логины" из ричбокса и отсюда их будут доставать обрабатывающие потоки
        static BlockingCollection<int> queue = new BlockingCollection<int>();
 
        static void Main(string[] args)
        {
            // Создаем шесть потоков, которые будут заниматься логином
            Task[] threads = new Task[6];
            for (int i = 0; i < threads.Length; i++)
            {
                int num = i + 1;
                threads[i] = Task.Factory.StartNew(() => ProcessQueue("Thread " + num));
            }
 
            // Создаем очередь "логинов"
            for (int i = 0; i < 100; i++)
            {
                queue.Add(i);
            }
 
            // Эта строчка заставит все слушающие потоки разблокироваться, когда в очереди не останется элементов.
            // На деле ее надо добавлять при завершении работы приложения - чтобы слушающие потоки не висели бесконечно.
            queue.CompleteAdding();
 
            // Ждем окончания работы всех потоков
            Task.WaitAll(threads);
 
            Console.WriteLine("All threads finished execution");
            Console.ReadLine();
        }
 
        // Добавляет элемент в очередь
        static void Enqueue(int value)
        {
            queue.Add(value);
        }
 
        // Удаляет и возвращает первый элемент в очереди
        static int Dequeue()
        {
            return queue.Take();
        }
 
        // Достает элементы из очереди и обрабатывает их
        static void ProcessQueue(object taskName)
        {
 
            while (true)
            {
                try
                {
                    // Достаем следующий элемент из очереди. Если элементов ноль и свойство очереди IsCompleted = false, поток будет заблокирован пока элементы не появятся.
                    int item = Dequeue();
 
                    // Делаем что нам нужно. В данном случае просто выводим полученный из очереди элемент в консоль. На деле здесь будут обрабатываться логины.
                    Console.WriteLine("{0}: processing {1}.", taskName, item);
 
                    // Допустим, один логин занимает 1 секунду.
                    Thread.Sleep(1000);
                }
                catch (InvalidOperationException)
                {
                    // Обеспечиваем выход из бесконечного цикла при завершении работы приложения
                    Console.WriteLine("{0} has finished working", taskName);
                    return;
                }
            }
        }
    }
}
2
12 / 12 / 1
Регистрация: 18.06.2011
Сообщений: 435
22.02.2012, 23:43  [ТС]
Столько методов решения одной "проблемы", что голова кружится.. ППЦ

Добавлено через 28 минут
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
 static void ProcessQueue(object taskName)
        {
 
            while (true)
            {
                try
                {
                    
                    int item = Dequeue();
 
                  
                    Console.WriteLine("{0}: processing {1}.", taskName, item);
                    textBox2.AppendText(taskname);  // к[B]ак получить доступ к элементу формы *[/B]
 
                    
                    Thread.Sleep(1000);
                }
                catch (InvalidOperationException)
                {
                    
                    Console.WriteLine("{0} has finished working", taskName);
                    return;
                }
            }
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
22.02.2012, 23:46
Цитата Сообщение от Radzhab Посмотреть сообщение
C#
1
textBox2.AppendText(taskname); // к[B]ак получить доступ к элементу формы *[/B]
Далеко не лучший способ задать вопрос. Особенно "*" вместо "?".

А по делу, сам же писал: Потоки: синхронизированный доступ к стеку (Invoke)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
22.02.2012, 23:46
Помогаю со студенческими работами здесь

Потоки и общий доступ к файлу
Господа, есть немного глуповатый код (делался для учебы). Почему выскакивает исключение из-за одновременного доступа к файлу. Ведь я же...

Как в C# сделать синхронизированный метод?
Есть у меня метод, который вызывается при возникновении определенного события. События могут следовать с коротким интервалом времени между...

Сокеты, потоки и доступ к элементам формы из дочернего потока
Добрый день. Задача &quot;на человеческом языке&quot; звучит так: при открытии дочерней формы устанавливается соединение с сервером и...

Синхронизированный доступ к списку
Документацию не учили читать? ...

Потоки. Доступ к переменным
Помогите с вопросом о видимости переменных. Я создал поток внутри класса Activity. Теперь не могу обратиться из потока к объявленым...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
Модель сукцессии микоризы
anaschu 24.01.2026
Решили писать научную статью с неким РОманом
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru