Многопоточная программа не отвечает

Вопрос:

У меня есть два потока, кроме основной нити. Оба они имеют бесконечные циклы, один из которых подготавливает растровые изображения, а другой применяет изменения к ui. Проблема в том, что когда я запускаю программу, она не отвечает на какие-либо данные.

    private WriteableBitmap _bmp;
private byte[] _pixelData;
private Image _img;
private int _stride;
private int _width, _height;
const int BYTES_OF_PIXEL = 4;
private Random _random;
private Mutex _mutex = new Mutex();

public MainWindow()
{
InitializeComponent();
Width = 480;
Height = 320;
canvas.Width = Width;
canvas.Height = Height;
WindowStartupLocation = WindowStartupLocation.CenterScreen;
_random = new Random();
_width = (int)this.Width;
_height = (int)this.Height;

var pixelCount = _width * _height;

_bmp = new WriteableBitmap(_width, _height, 96, 96, PixelFormats.Bgra32, null); // writeable bmp
_pixelData = new byte[pixelCount * BYTES_OF_PIXEL]; // all pixels
_stride = _width * BYTES_OF_PIXEL; // bytes per row
_img = new Image(); // displayed image

RenderOptions.SetBitmapScalingMode(_img, BitmapScalingMode.LowQuality);
RenderOptions.SetEdgeMode(_img, EdgeMode.Aliased);
canvas.Children.Add(_img);

var bufferThread = new Thread(PrepareScreenWrapper);
var renderThread = new Thread(RenderScreenWrapper);

bufferThread.Start();
renderThread.Start();
}

private void PrepareScreen()
{
while (true)
{
var a = (byte)_random.Next(255);
var r = (byte)_random.Next(255);
var g = (byte)_random.Next(255);
var b = (byte)_random.Next(255);
var color = Color.FromArgb(a, r, g, b);

for (var y = 0; y < _height; y++)
{
for (var x = 0; x < _width; x++)
{
var index = (y * _stride) + (x * 4);
_pixelData[index] = color.B;
_pixelData[index + 1] = color.G;
_pixelData[index + 2] = color.R;
_pixelData[index + 3] = color.A;
}
}

_mutex.WaitOne();
_bmp.WritePixels(new Int32Rect(0, 0, _width, _height), _pixelData, _stride, 0);
_mutex.ReleaseMutex();
}
}

private void RenderScreen()
{
while (true)
{
_mutex.WaitOne();
_img.Source = _bmp;
_mutex.ReleaseMutex();
}
}

private delegate void PrepareScreenCallback();
private void PrepareScreenWrapper()
{
var prepareScreenCallback = new PrepareScreenCallback(PrepareScreen);
Application.Current.Dispatcher.BeginInvoke(prepareScreenCallback, DispatcherPriority.Render);
}
private delegate void RenderScreenCallback();
private void RenderScreenWrapper()
{
var renderScreenCallback = new RenderScreenCallback(RenderScreen);
Application.Current.Dispatcher.BeginInvoke(renderScreenCallback, DispatcherPriority.Render);
}

Лучший ответ:

Посмотрев на ваш код, я переустановил его и использовал TPL и Tasks для лучшего управления потоками. Я также объединил Buffer и Render, поскольку мьютексы только усложняют вопросы, и оба могут произойти в одной функции, поскольку она уже отключена от потока пользовательского интерфейса.

NB: Task.Delay() перестает спамить поток пользовательского интерфейса, что может привести к его невосприимчивости. Вы должны быть осторожны, чтобы не перегружать потоки пользовательского интерфейса, поскольку это может привести к блокировке пользовательского интерфейса.

Задача в TPL дает намного лучшую api для mutlithreading. Я бы настоятельно рекомендовал их прочитать.

private WriteableBitmap _bmp;
    private byte[] _pixelData;
    private Image _img;
    private int _stride;
    private int _width, _height;
    const int BYTES_OF_PIXEL = 4;
    private Random _random;
    private Mutex _mutex = new Mutex();

    public MainWindow()
    {
      InitializeComponent();
      Width = 480;
      Height = 320;
      canvas.Width = Width;
      canvas.Height = Height;
      WindowStartupLocation = WindowStartupLocation.CenterScreen;
      _random = new Random();
      _width = (int)this.Width;
      _height = (int)this.Height;

      var pixelCount = _width * _height;

      _bmp = new WriteableBitmap(_width, _height, 96, 96, PixelFormats.Bgra32, null); // writeable bmp
      _pixelData = new byte[pixelCount * BYTES_OF_PIXEL]; // all pixels
      _stride = _width * BYTES_OF_PIXEL; // bytes per row
      _img = new Image(); // displayed image

      RenderOptions.SetBitmapScalingMode(_img, BitmapScalingMode.LowQuality);
      RenderOptions.SetEdgeMode(_img, EdgeMode.Aliased);
      canvas.Children.Add(_img);

      var progress = new Progress<object>(_ =>
      {
        _bmp.WritePixels(new Int32Rect(0, 0, _width, _height), _pixelData,_stride, 0);
        _img.Source = _bmp;
      });

      var bufferTask = Task.Factory.StartNew(() => Process(progress));
    }

    private void Process(IProgress<object> progress)
    {
      while (true)
      {
        var a = (byte) _random.Next(255);
        var r = (byte) _random.Next(255);
        var g = (byte) _random.Next(255);
        var b = (byte) _random.Next(255);
        var color = Color.FromArgb(a, r, g, b);

        for (var y = 0; y < _height; y++)
        {
          for (var x = 0; x < _width; x++)
          {
            var index = (y*_stride) + (x*4);
            _pixelData[index] = color.B;
            _pixelData[index + 1] = color.G;
            _pixelData[index + 2] = color.R;
            _pixelData[index + 3] = color.A;
          }
        }

        progress.Report(null);
        Task.Delay(1000);
      }
    }

Оцените статью
TechArks.Ru
Добавить комментарий