Как настроить синхронизацию потоков C#?
подскажите пожалуйста, каким образом можно останавливать все потоки кроме одного, который удовлетворяет условию в определенный момент времени и затем как условие не выполняется снова запускать все потоки используя синхронизацию потоков.
В приложение по примеру № 3 добавить вертикальную область. Внутри области может находиться только один шарик, другие шарики ожидают, пока область не освободится. Применить синхронизацию потоков.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
class Ball
{
static object locker = new object();
public int x, y; // координаты
int dx, dy; //приращение координат-определяет скорость
int w, h; //ширина высота шарика
public bool live = true; // признак жизни
public delegate void DlTp();// Объявление типа (делегат) и
//создание пока что пустой ссылки для организации в последующем
// с помощью ее вызова функции Invalidate()для главного потока
public DlTp dl;
public Thread thr; //Создание ссылки на потоковый объект
// потоковая функция
public void FnThr()
{
while (live)
{ //здесь отражемся от границ области
if (x < 0 || x > 200) dx = -dx;
if (y < 0 || y > 200) dy = -dy;
//здесь пересчитываем координаты
x += dx;
y += dy;
Thread.Sleep(30);//спим
dl(); //вызываем с помощью делегата Invalidate()
}
w = h = 0; //схлопываем шарик
dl(); //вызываем с помощью делегата Invalidate()
}
//функция рисования шарика
public void DrawBall(Graphics dc)
{
dc.DrawEllipse(Pens.Magenta, x, y, w, h);
}
//конструктор класса
public Ball(int xn, int yn, int wn, int hn, int dxn, int dyn)
{
x = xn; y = yn; w = wn; h = hn; dx = dxn; dy = dyn;//инициализируем
thr = new Thread(new ThreadStart(FnThr)); //создаем потоковый объект
live = true; //устанавливаем признак жизни
thr.Start(); //запускаем поток
}
}
Ball[] bl = new Ball[10];//массив пустых ссылок типа Ball
public Form1()
{
InitializeComponent();
for (int j = 0; j < bl.Length; j++)
{
//создаем потоковые объекты
bl[j] = new Ball(j, j * 10, 10, 10, j + 1, j + 1);
//подписываемся на событие
bl[j].dl += new Ball.DlTp(Invalidate);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int j = 0; j < bl.Length; j++)
{
bl[j].DrawBall(e.Graphics);//рисуем
if(bl[j].x > 200)
{
for (int i = 0; i < bl.Length; i++)
{
if (bl[i] != bl[j])
{
lock (typeof(Ball)) bl[i].FnThr();
Console.WriteLine(bl[j].thr.ThreadState);
}
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
for (int j = 0; j < bl.Length; j++)
{
bl[j].live = false;// Уничтожаем потоки
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
for (int j = 0; j < bl.Length; j++)
{
bl[j].live = false;//уничтожаем потоки
}
}
}
}
Ответы (1 шт):
Не используйте вложенные типы, это будет вас только путать и стимулировать написание грязного кода. Располагайте классы рядом друг с другом, а не внутри.
Вот так
public class Ball
{
}
public partial class Form1 : Form
{
}
В идеале эти классы нужно расположить в разных C# файлах.
Решение простое.
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int j = 0; j < bl.Length; j++)
{
if (bl[j].live) // если неживой, игнорируем его
{
if(bl[j].x > 200) // если пересек
bl[j].live = false; // убиваем
else
bl[j].DrawBall(e.Graphics); // иначе рисуем
}
}
}
Вместо пары x,y используйте структуру Point
public class Ball
{
public Point Position;
}
Избегайте сокращений, код из непонятно почему так названных переменных (FnThr => RunLoop) очень сложно читать.
Вот, смотрите разницу:
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int j = 0; j < balls.Length; j++)
{
if (balls[j].IsLive)
{
if(balls[j].Position.X > 200)
balls[j].IsLive = false;
else
balls[j].Draw(e.Graphics);
}
}
}
Не экономьте буквы, от этого код быстрее работать не будет.
Что касается самого условия задачи, заведите еще одно поле, чтобы шарики можно было не только убивать но и на паузу ставить.
public bool IsActive;
public void RunLoop()
{
while (IsLive)
{
if (x < 0 || x > 200) dx = -dx;
if (y < 0 || y > 200) dy = -dy;
x += dx;
y += dy;
do
{
Thread.Sleep(30); // спим
} while (!IsActive); // пока деактивирован
OnPositionChanged();
}
w = h = 0;
OnPositionChanged();
}
Или даже так
private ManualResetEventSlim _activeLock = new ManualResetEventSlim(true);
public void RunLoop()
{
while (IsLive)
{
if (x < 0 || x > 200) dx = -dx;
if (y < 0 || y > 200) dy = -dy;
x += dx;
y += dy;
Thread.Sleep(30); // спим
_activeLock.Wait();
OnPositionChanged();
}
w = h = 0;
OnPositionChanged();
}
public void Deactivate()
{
_activeLock.Reset();
}
public void Activate()
{
_activeLock.Set();
}