简体   繁体   中英

Multithreaded program does not respond

I have two threads except main ui thread. They both have infinite loops, one of them prepares bitmap and the other one apply changes to the ui. The problem is, when I start the program, it does not respond any input.

    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);
    }

Having looked at you code I have re-factored it and used TPL and Tasks for better thread management. I've also combined the Buffer and Render as the mutex only complicated matters and both can happen in a single function as it is already off the UI thread.

NB: Task.Delay() stops spamming the UI thread which would cause it to be unresponsive. You must be careful to not overload the UI threads as this could cause the UI to lockup.

Task in TPL give much better api's for mutlithreading. I would strong recommend reading up on them.

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);
      }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM