Страница: 1 |
Страница: 1 |
Вопрос: Нужна помощь с многопоточностью.
Добавлено: 22.11.10 11:44
Автор вопроса: Oleg
Имеется программа. Которая (как я планировал) должна считать от 1 до .. значения заданного пользователем. Выполняться это должно в количестве потоков заданных пользователям. Результат записывается в ListBox в формате:
[номер потока] : [число]
[визуальный разделитель между потоками вида "======"]
На данный момент программа работает не корректно, а именно делает следующий вывод:
(При количестве потоков - 3, при счете от 1 до 9)
0 : 1
0 : 2
0 : 3
0 : 4
0 : 5
0 : 6
0 : 7
0 : 8
0 : 9
=============
1 : 1
1 : 2
1 : 3
1 : 4
1 : 5
1 : 6
1 : 7
1 : 8
1 : 9
=============
2 : 1
2 : 2
2 : 3
2 : 4
2 : 5
2 : 6
2 : 7
2 : 8
2 : 9
Как мне добиться корректного вывода? Выглядеть он должен так:
0 : 1
=========
1 : 2
=========
2 : 3
=========
0 : 4
=========
1 : 5
=========
2 : 6
=========
0 : 7
=========
1 : 8
=========
2 : 9
--------
Вот исходник (так же для удобочитаемости можете скачать его тут (Visual Studio 2010, с коментами на инглиш) - http://rapidshare.com/files/432386064/Threads.zip):
Imports System.Threading
Public Class Form1
Private Delegate Sub addToListBox_d(ByVal result As String)
Private threadCounters As New List(Of Integer)()
Private maxCount As Integer
Private threadLock As New Object
Private Sub addToListBox(ByVal result As String)
If Me.InvokeRequired() Then
Me.Invoke(New addToListBox_d(AddressOf addToListBox), New Object() {result})
Else
ListBox1.Items.Add(result)
End If
End Sub
Private Sub DoWork(ByVal state As Object)
Monitor.Enter(threadLock)
Try
Dim threadIndex As Integer = Integer.Parse(Thread.CurrentThread.Name)
Dim count As Integer = threadCounters(threadIndex)
For loopCount As Integer = 1 To maxCount
addToListBox(Thread.CurrentThread.Name + " : " + loopCount.ToString())
Next
addToListBox("==========")
Finally
Monitor.Exit(threadLock)
End Try
End Sub
Private Sub StartButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartButton.Click
Dim counter As Integer = 0
Dim threadCount As Integer = Integer.Parse(cboNoOfThreads.Text)
If Integer.TryParse(txtMaxCount.Text, maxCount) Then
Do While (counter < threadCount)
Dim t As Thread = New Thread(AddressOf DoWork)
t.IsBackground = True
t.Name = counter.ToString()
threadCounters.Add(0)
t.Start(counter)
counter += 1
Loop
End If
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
cboNoOfThreads.SelectedIndex = 0
End Sub
End Class
Ответы
Всего ответов: 15
Номер ответа: 1
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #1
Добавлено: 22.11.10 12:37
как раз таки она работает корректно согласно тому коду,что ты написал..
поскольку ты используешь блокировки,то следующий поток НЕ может запуститься, пока не завершит работу предыдущий..
чтобы все зарабоатло так как тебе нужно закомментируй строки:
Номер ответа: 2
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #2
Добавлено: 22.11.10 12:38
Monitor.Enter(threadLock)
Monitor.Exit(threadLock)
в данном случае они не нужны..
Номер ответа: 3
Автор ответа:
Oleg
Вопросов: 1
Ответов: 3
Профиль | | #3
Добавлено: 22.11.10 13:59
Ситуация действительно проясняется. Но с выводом не получается.
--Текущий результат--
0 : 0
1 : 0
2 : 0
0 : 1
1 : 1
2 : 1
0 : 2
1 : 2
2 : 2
...
--------
Номер ответа: 4
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #4
Добавлено: 22.11.10 14:15
1 : 0
2 : 0
В данном случае потоки работают независимо друг от друга.. и каждый считает свою переменную. Это их типичное поведение.
Чтоб не мутить воду попытайся объяснить задачу.. ЧТО ты пытаешься сделать.. Потому как твое желание заставить работать потоки следующим образом:
=========
1 : 2
=========
2 : 3
мягко говоря вызывает недоумение.. Либо ты не понимаешь сути потоков и задачи которые они выполняют, либо твоя задача достаточно не тривиальная и требует использование механизмов синхронизации потоков.
Номер ответа: 5
Автор ответа:
Oleg
Вопросов: 1
Ответов: 3
Профиль | | #5
Добавлено: 22.11.10 14:29
Вообще эта программа для экспериментов над потоками. А целевой софт должен будет выполнять web запросы в многопоточном режиме.
К примеру софт по загрузке новостей:
http://site.com/news/?page=1
.....
до http://site.com/news/?page=3000
Тоесть требуется чтобы каждый поток выполнял свой запрос.
К примеру заданно 5 потоков:
0 - http://site.com/news/?page=1
1 - http://site.com/news/?page=2
2 - http://site.com/news/?page=3
3 - http://site.com/news/?page=4
4 - http://site.com/news/?page=5
после загруки этих страниц нужно чтобы потоки продолжали в том же духе до page=3000.
0 - http://site.com/news/?page=6
1 - http://site.com/news/?page=7
2 - http://site.com/news/?page=8
3 - http://site.com/news/?page=9
4 - http://site.com/news/?page=10
.....
У меня в программировании 2 проблемы - регулярки и многопоточность )) Трудно въехать без хорошего примера.
Номер ответа: 6
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #6
Добавлено: 22.11.10 14:51
ну как я и думал.. стандартная задача не требующая очередности выполнения..
В твоем случае правильнее будет сделать так:
1. Создать очередь
2. Заполнить ее URLами
3. Запустить N-потоков в зависимости от ширины твоего канала.. Потому что если запустить слишком много потоков, они не смогут одновременно выполнить много запросов и будут отваливаться по timeout
Далее в потоке происходит следуещее:
- Блокируешь очередь через Lock (это аналог Monitor.Enter/Exit)
- Проверяешь количестов элементов в очереди, если там есть элементы,то достаешь очередной URL (снимаешь блокировку с очереди,чтоб другие потоки могли работать с нею)
- Выполняешь запрос
- Обрабатываешь полученную страницу (сохраняешь,парсишь и т.д..)
- и так крутишь цикл до тех пор пока очередь не опустеет..
Таким образом 5-10 потоков у тебя будут работать с одной очередью и загрузят все страницы..
Номер ответа: 7
Автор ответа:
Oleg
Вопросов: 1
Ответов: 3
Профиль | | #7
Добавлено: 22.11.10 15:47
Спасибо, буду пробовать, правда с пулами вообще не знаком.
Номер ответа: 8
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #8
Добавлено: 22.11.10 16:06
с пулами тоже ничего сложного.. не разберешься - пиши,объясню..
Номер ответа: 9
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #9
Добавлено: 22.11.10 16:22
Пул потоков здесь вообще не нужен.
Если ты пишешь на 4.0, то задача очень приятно решается на классе BlockingCollection. Если на чем-то более старом, то надо мутить со стандартной Queue<T>, которая не является потокобезопасной, и для корректной ее работы в таком сценарии нужно навешивать целую кучу синхронизаций.
Номер ответа: 10
Автор ответа:
AgentFire
ICQ: 192496851
Вопросов: 75
Ответов: 3178
Профиль | | #10
Добавлено: 22.11.10 16:36
SynсLock на 3.5 не дает потокобезопасность?
Номер ответа: 11
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #11
Добавлено: 22.11.10 17:06
дает, если писать прямыми руками..
Номер ответа: 12
Автор ответа:
AgentFire
ICQ: 192496851
Вопросов: 75
Ответов: 3178
Профиль | | #12
Добавлено: 22.11.10 23:27
ну дык и зачем тогда все эти ваши мьютексы
Номер ответа: 13
Автор ответа:
Artyom
Разработчик
Вопросов: 130
Ответов: 6602
Профиль | | #13
Добавлено: 23.11.10 00:52
Зачем все эти ваши SyncLock когда есть BlockingCollection?
Номер ответа: 14
Автор ответа:
EROS
Вопросов: 58
Ответов: 4255
Профиль | | #14
Добавлено: 23.11.10 09:06
BlockingCollection есть только в FW 4.0, и далеко не все его юзают и считают необходимым переходить на него только из за BlockingCollection
Номер ответа: 15
Автор ответа:
mihar
ICQ: Днепропетровск...
Вопросов: 0
Ответов: 1
Профиль | | #15
Добавлено: 25.11.10 15:00
del