Проблема в многопоточной программе
Дано задание которое звучит следующим образом:
С клавиатуры вводится число роботов, собирающих игрушки, и число наборов для сборки. Число наборов для сборки игрушек должно превышать число роботов не менее чем в 100 раз. Каждый робот собирает игрушку за некоторое время, попадающее в диапазон, введенный с клавиатуры пользователем. Когда игрушка собрана, робот берет новый набор для сборки игрушки, пока все наборы не будут собраны. Каждый робот работает в отдельном потоке.
Требования:
В ListBox необходимо выводить информацию о ходе процесса. События, которые необходимо отразить в ListBox:
- робот №n начал сбор набора №m. Время сбора набора: x минут;
- робот №n закончил сбор набора №m;
- наборы для сборки закончились.
Код:
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public bool stop;
List<Thread> threads = new List<Thread>();
int[] robots;
int numberSets = 0;
Random random = new Random();
object locker = new object();
//List<int> sets = new List<int>();
//List<int> setss;
public Form1()
{
InitializeComponent();
stop = false;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
foreach (Thread thread in threads)
{
thread.Abort();
}
}
private void button1_Click(object sender, EventArgs e)
{
if (Convert.ToInt32(numberRobots.Text) * 100 <= Convert.ToInt32(numberSet.Text))
{
robots = new int[Convert.ToInt32(numberRobots.Text)];
for (int i = 0; i < Convert.ToInt32(numberRobots.Text); i++)
{
robots[i] = i + 1;
}
for (int i = 0; i < Convert.ToInt32(numberRobots.Text); i++)
{
threads.Add(new Thread(new ParameterizedThreadStart(CreatSet)));
threads[i].Name = $"Робот {i + 1}";
threads[i].Start(Convert.ToInt32(robots[i]));
}
}
else
{
Console.WriteLine("Неправильно!");
}
}
public void CreatSet(object obj)
{
int numberRobot = (int)obj;
while (numberSets != Convert.ToInt32(numberSet.Text))
{
lock (locker)
{
numberSets++;
infAssembly.Items.Add($"• {Thread.CurrentThread.Name} начал сбор набора №{numberSets}. Время сбора набора: {random.Next(50, 100)} секунд;"); //<-- Ошибка
}
infAssembly.Items.Add($"• {Thread.CurrentThread.Name} закончил сбор набора №{numberSets}.");
Thread.Sleep(random.Next(50, 100));
}
infAssembly.Items.Add("•Наборы для сборки закончились.");
}
}
}
Но при его выполнении всегда появляется проблема. Каждый раз при нажатии кнопки, появляется необработанное исключение, приведённое на скриншоте, ссылающееся на 88ю строчку блока(отметил в коде). Подскажите, пожалуйста, как мне исправить это исключение?
Возникающее исключение:
System.InvalidOperationException: "Недопустимая операция в нескольких потоках: попытка доступа к элементу управления `infAssembly` не из того потока, в котором он был создан"
Ответы (1 шт):
Чтобы исправить ошибку Попытка доступа не из того потока....
можно использовать Invoke
(вот вопрос с объяснением).
Используется Invoke
если надо установить/передать какое-либо значение элементу, получать значения можно без него.
В вашем случае использование такое (переменную message
создаю отдельно, чтобы получить правильное Thread.CurrentThread.Name
):
...
var message = $"• {Thread.CurrentThread.Name} начал сбор набора №{numberSets}. Время сбора набора: {random.Next(50, 100)} секунд;";
Invoke((MethodInvoker)delegate
{
infAssembly.Items.Add(message);
});
...