【问题标题】:WinRT: Running concurrently two tasks that share resourcesWinRT:同时运行两个共享资源的任务
【发布时间】:2014-05-10 08:19:46
【问题描述】:

我正在开发一个 WinRT C# 应用程序。我有一个每秒引发 15-30 次的事件。这个事件为我提供了一个字节数组参数(实际上是字节[]中的一个图像):

void FrameArrived(object sender, byte[] pixels)
{
    // 1. Create a bitmap and render it on an <Image> element (UI thread).
    DisplayBitmap(pixels);

    // 2. Pass the byte array to a method for video recording.
    RecordBitmap(pixels);
}

DisplayBitmapRecordBitmap 都是繁重的进程,并且 UI 会变慢。

如果我只调用其中一种方法,一切正常。

请记住,此事件每秒引发 15-30 次。

我需要一种方法来并行运行这两种方法。我尝试过使用 Dispatcher、Parallel.Invoke 和 ThreadPool,但效果不佳。

提前谢谢你。

【问题讨论】:

  • 这两个都只是从字节数组中读取吗? FrameArrived 完成后,字节数组是否会被重用/变异?大概 DisplayBitmap 需要在 UI 线程上,但 RecordBitmap 不需要?
  • 嗨乔恩。字节数组仅用于显示位图,也由录像机处理。 FrameArrived 完成后我不需要它。 DisplayBitmap 在 Image UI 元素上呈现位图,所以我猜它必须在 UI 线程上运行。其实,我不在乎,只要结果足够顺利:)
  • 为什么不直接将“RecordBitmap”传递给后台线程(Task.Factory.StartNew 或类似线程)?
  • 如果我理解正确的逻辑,您应该保持 DisplayBitmap 原样并让 RecordBitmap 将像素数组推送到线程安全列表中。然后让另一个线程只处理列表中的项目。这将使像素阵列的记录保持有序。
  • McGarnale:我已经这样做了,虽然 UI 线程变慢了。乔恩:您能否详细说明您的解决方案或给我一个使用示例?非常感谢大家:-)

标签: c# parallel-processing windows-runtime windows-store-apps


【解决方案1】:

如果您需要按顺序记录像素数组,那么您不能只为每次调用此函数启动一个新线程,因为无法保证线程将按顺序运行。这个想法是尽可能快地将项目推送到列表中,然后让另一个线程以自己的速度处理这些项目。这只会有助于记录部分代码,如果您尝试渲染的图像数量超过 UI 线程可以处理的数量,那就是另一个问题了。

    void FrameArrived(object sender, byte[] pixels)
    {
        //push pixels into list
        lock (_pixelList)
        {
            _pixelList.Add(pixels);
        }
        _waitHandle.Set();


        // 1. Create a bitmap and render it on an <Image> element (UI thread).
        DisplayBitmap(pixels);

        // 2. Pass the byte array to a method for video recording.
        //RecordBitmap(pixels);
    }

    AutoResetEvent _waitHandle = new AutoResetEvent(false);
    List<byte[]> _pixelList = new List<byte[]>();
    bool _stop = false;
    void StartProcessPixelsThread()
    {
        Task.Run(() =>
        {
            while (!_stop)
            {
                _waitHandle.WaitOne();
                while (true)
                {
                    byte[] pixels;

                    lock (_pixelList)
                    {
                        if (_pixelList.Count > 0)
                        {
                            pixels = _pixelList[0];
                            _pixelList.RemoveAt(0);
                        }
                        else
                        {
                            break;
                        }
                    }
                    RecordBitmap(pixels);
                }
            }
        });
    }
    void StopProcessPixelsThread()
    {
        _stop = true;
        _waitHandle.Set();
    }

【讨论】:

  • 仍然存在与我正在使用的 RecordVideo 功能有关的阻塞问题。我设法使用@McGarnagle 所说的让它工作。但是,您完全正确,为每个调用创建一个新线程并不能保证它们会按顺序运行。我会用你提出的答案做更多的工作。再次感谢您。
  • 听起来您的 RecordBitmap 方法也需要 UI 线程。
【解决方案2】:

我终于用 ConcurrentQueue 做到了。这与@Jon 提出的略有不同。再次感谢大家的帮助!

// Stores the frames coming from different threads.
ConcurrentQueue<byte[]> _queue = new ConcurrentQueue<byte[]>();

// Begins recording.
public void Start()
{
    if (!IsRecording)
    {
        IsRecording = true;
    }

    Task.Run(() =>
    {
        while (IsRecording || _queue.Count > 0)
        {
            byte[] pixels;

            if (_queue.TryDequeue(out pixels))
            {
                RecordBitmap(pixels);
            }
        }
    });
}

// Stops recording.
public void Stop()
{
    if (IsRecording)
    {
        IsRecording = false;
    }
}

// Updates the frames (called from FrameArrived).
public void Update(byte[] pixels)
{
    _queue.Enqueue(pixels);
}

【讨论】:

    猜你喜欢
    • 2014-10-03
    • 1970-01-01
    • 1970-01-01
    • 2014-04-06
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多