Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/11: Рейтинг темы: голосов - 11, средняя оценка - 4.64
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
1

Корректировка работы нескольких потоков с одним циклом

17.04.2012, 11:48. Показов 1960. Ответов 10
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Привет. Ребята, нужна ваша помощь. Не могу распаралелить поток.

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
namespace potok
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        delegate void listLogPotokDelegate(string text);
 
        private void listLogPotok(string text)  
        { 
            if (InvokeRequired) 
            { 
                BeginInvoke(new listLogPotokDelegate(listLogPotok), new object[] { text }); return; 
            } 
            else 
            { 
                listBox1.Items.Add(text);
            } 
        }
 
        private void filePotok()
        {
              Random rnd = new Random();
 
                Thread.Sleep(rnd.Next(1000, 10000));
                for (int i = 0; i < 10; i++)
                {
                      listLogPotok(Thread.CurrentThread.Name + ": " + i.ToString());
                }
 
                Thread.Sleep(rnd.Next(1000, 10000));
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            Thread[] th = new Thread[modems.Count];  // modems.Count - массив модемов
            for (int i = 0; i < modems.Count; i++)
            {
                th[i] = new Thread(filePotok);
                th[i].IsBackground = true;
                Thread.Sleep(1000);
                th[i].Start();
            }
        }
    
    }
}

В чем собственно состоит проблема.
Сейчас каждый поток выводит числа от 0 до 9, а
мне нужно чтоб выводило следующие записи

th0 = 0;
th1 = 1;
th3 = 2;
th0 = 4;
th2 = 3;
th0 = 6;
th2 = 5; ......

то есть заданное количество потоков вместе работали с одним цыклом. Один поток выводит одно число, второй второе, третий четвертее, четвертый третее и т.д.

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

Если кому то интересно - то это программа обзвона обенентов под 5 модемов. Каждый модем - отдельныя ветка. То есть каждый модем берет телефон с массива и звонит на него. Такая операция должна паралельно выполнятся под 5 модемов. если я буду явно задавать для каждого модема массив телефнов, то может оказатся, что один можем получит 500 телефнов, второй 30, а все остальные вообще ничего. Поэтому мне и нужно чтоб 5 потоков работали с одной процедурой и работать под 5 потоков с одной процедурой
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.04.2012, 11:48
Ответы с готовыми решениями:

Создание нескольких элементов одним циклом
Доброго времени суток всем! Есть задание у меня. Под каждое изображение на странице сайта надо...

Отображение общего прогресса работы нескольких потоков на одном progressbar
В программе параллельно работают три потока, каждый из которых выполняет одинаковый объем работы,...

Вывод результата работы нескольких потоков в Memo - выводится данные только последнего
Всем привет. По нажатию кнопки я создаю определенное количество потоков. mythread :=...

Сделать с одним циклом
Дана программа: CLS PRINT “ Ряд чётных чисел:” PRINT “ Пошаговая сумма чётных чисел:” FOR i...

10
Эксперт .NET
17689 / 12874 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
17.04.2012, 14:25 2
Сделайте одну общую коллекцию с телефонами и сколько-то там потоков.
Пусть эти потоки, синхронизируясь, достают по одному элементу из коллекции и звонят на него, пока все элементы не закончатся.

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
ConcurrentQueue<int> queue = new ConcurrentQueue<int>();
void Main()
{
   for (int i = 0; i < 10; i++) queue.Enqueue(i);
   Thread[] threads = new Thread[5];
   for (int i = 0; i < threads.Length; i++)
   {
      threads[i] = new Thread(Dial);
      threads[i].Start();
   }
   foreach (Thread th in threads) th.Join();
   Console.WriteLine("Done");
   Console.ReadKey();
}
 
static void Dial()
{
    int number;
    while (true)
    {
         if (queue.TryDequeue(out number)) Console.WriteLine(number);
         else return;
    }
}
Таким образом избегаете проблемы, когда один мопед уже отзвонился по всем номерам и бьет баклуши, а остальные еще пыхтят, пытаясь дозвониться.
1
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
17.04.2012, 21:48  [ТС] 3
все бы ничего но в строке

C#
1
if (queue.TryDequeue(out number)) Console.WriteLine(number);
у меня нету компонента "TryDequeue"
0
Эксперт .NET
17689 / 12874 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
17.04.2012, 22:02 4
А в первой строке у вас, получается, есть ConcurrentQueue?
0
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
18.04.2012, 09:16  [ТС] 5
да, этой тоже нету. Все написано под Framework 3.5
твой код под 4-ый. Пасиб, в режиме теста все работает, попробую отточить код под 4-й фрейм.
0
Эксперт .NET
17689 / 12874 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
18.04.2012, 12:03 6
Под 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
static Queue<int> queue = new Queue<int>();
static object queueLock = new object();
 
static void Main()
{
    for (int i = 0; i < 10; i++) queue.Enqueue(i);
    Thread[] threads = new Thread[5];
    for (int i = 0; i < threads.Length; i++)
    {
        threads[i] = new Thread(Dial);
        threads[i].Start();
    }
    foreach (Thread th in threads) th.Join();
    Console.WriteLine("Done");
    Console.ReadKey();
}
 
static void Dial()
{
    int number;
    while (true)
    {
        lock (queueLock)
        {
            if (queue.Count > 0)
                number = queue.Dequeue();
            else return;
        }
        Console.WriteLine(number);
    }
}
1
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
18.04.2012, 13:08  [ТС] 7
kolorotur, пасиб виручил.
ща разберусь с кодом. потому что с очередями еще не работал.

Может кому-то пригодится, код работы 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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace fiveThreads
{
    class Program
    {
        const int N = 20;
        static int[] array  = new int[N];
       static int  PtrToArray = 0;
      static object ttt = new object();
 
      static void InitializeArray()
      {
          for (int i = 0; i < N; i++)
          {
              array[i] = i;
          }
      }
 
        static void Main(string[] args)
        {
            InitializeArray();
 
 
            for (int i = 0; i < 5; i++)
            {
                Thread th = new Thread(new ThreadStart(proc));
                th.Start();
            }
            Console.ReadLine();
        }
 
 
       static void proc()
        {
           Random rnd = new Random();
            while (PtrToArray < N)
            {
                int curVal;
                lock (ttt)
                {
                    curVal = array[PtrToArray++];
                }
                    Console.WriteLine("Potok {0}: chislo {1}", Thread.CurrentThread.ManagedThreadId, curVal);
                Thread.Sleep(rnd.Next(2000));
                
            }
        }
                
    }
}
0
Эксперт .NET
17689 / 12874 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
18.04.2012, 13:16 8
У вас не синхронизирован доступ к PtrToArray во время проверки.
Может возникнуть ситуация с выходом за пределы массива.
0
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
19.04.2012, 14:44  [ТС] 9
так он же лочится при при каждом новом переходе:

C#
1
2
3
4
 lock (ttt)
    {
       curVal = array[PtrToArray++];
    }
я не говорю, что вы не правы, просто не могу понять почему такое может произойти.
не могу смоделировать такую ситуацию, когда он может это сделать.
0
Эксперт .NET
17689 / 12874 / 3366
Регистрация: 17.09.2011
Сообщений: 21,138
19.04.2012, 15:24 10
Он лочится, но только при инкременте, а при проверке - нет.
Ситуацию смоделировать очень легко:
Итак, у нас есть следующий цикл:
C#
1
2
3
4
5
6
7
8
9
10
11
            while (PtrToArray < N)
            {
                int curVal;
                lock (ttt)
                {
                    curVal = array[PtrToArray++];
                }
                    Console.WriteLine("Potok {0}: chislo {1}", Thread.CurrentThread.ManagedThreadId, curVal);
                Thread.Sleep(rnd.Next(2000));
                
            }
Этот цикл выполняется одновременно, допустим, из двух потоков.
Предположим, что происходит обход массива из десяти элементов и на данный момент значение PtrToArray = 9, N = 10.
Начинаем отслеживание:
1. Первый поток делает проверку. Проверка проходит.
2. Второй поток делает проверку. Проверка проходит.
3. Первый поток создает переменную curVal.
4. Второй поток создает переменную curVal.
5. Первый поток заходит в критическую зону.
6. Второй поток пытается зайти в критическую зону и замораживается, т.к. в ней уже первый поток.
7. Первый поток достает элемент под индексом 9, присваивает его переменной curVal и увеличивает значение PtrToArray до 10-и.
8. Первый поток выходит из критической зоны и выводит сообщение.
9. Второй поток заходит в критическую зону.
10. Второй поток пытается достать элемент под индексом 10 (он ведь уже раньше прошел проверку и "предполагает", что PtrToArray все еще < N) и чпок - вылетает IndexOutOfRangeException.

Исправить можно, делая проверку и присваивание значения элементу в критической зоне:
C#
1
2
3
4
5
6
7
8
9
10
11
12
            while (true)
            {
                int curVal;
                lock (ttt)
                {
                    if (PtrToArray < N) curVal = array[PtrToArray++];
                    else return;
                }
                    Console.WriteLine("Potok {0}: chislo {1}", Thread.CurrentThread.ManagedThreadId, curVal);
                Thread.Sleep(rnd.Next(2000));
                
            }
1
218 / 212 / 63
Регистрация: 17.04.2012
Сообщений: 382
19.04.2012, 23:17  [ТС] 11
Добавлено через 2 минуты
все, въехал.! спасибо, вам, за розъяснения.
0
19.04.2012, 23:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.04.2012, 23:17
Помогаю со студенческими работами здесь

Программа с одним циклом
CLS DIM A(5) PRINT “ Создание массива” FOR i = 1 TO 5 INPUT “ Ввести числа: “, A( i ) NEXT...

Замедление работы потоков если запущено несколько потоков
Есть отдельный поток который движет красным квадратом. Он каждую миллисекунду меняет положение...

Создание потоков циклом
У меня возник вопрос. Надо сделать программу в которой каждая математическая функция создаётся в...

Заполнить матрицу одним циклом
Нужно заполнить матрицу заданного размера в одном цикле (не использовать вложенные for). Я...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru