簡體   English   中英

是否有線程的await語句?

[英]Is there an await statement for threads?

嗨,我想知道是否有類似await語句的東西,它與任務一起使用,我可以用c#中的線程實現?

我想做的是:

啟動線程A,計算一些數據並將結果放在變量x 之后,變量x被轉移到另一個線程B,同時線程A再次開始計算一些數據,而線程B開始另一個計算結果x

更新:好的,似乎有一些混亂,所以我的描述會更准確:

我使用兩個產生數據的傳感器。 需要以檢索SensorA數據的方式檢索數據(這需要很長時間),之后必須在另一個線程中檢索來自SensorB的數據,而SensorA繼續檢索另一個數據塊。 問題是我不能將兩個傳感器的數據排隊在同一隊列中,但我需要將兩個傳感器的數據存儲在一個數據結構/對象中。

我的想法是這樣的:

  1. 從線程A中的傳感器A獲取數據
  2. 將結果提供給線程B並重新啟動線程A.
  3. 當線程A再次運行時,線程B從傳感器B獲取數據並計算來自傳感器A和B的數據

您可以假設線程A總是需要比線程B更長的時間

正如我在評論中所說。 這看起來像經典的制作人/消費者,我們可以使用它,例如BlockingCollection

這是對該頁面中的示例的輕微修改:

BlockingCollection<Data> dataItems = new BlockingCollection<Data>(100);

// "Thread B"
Task.Run(() => 
{
    while (!dataItems.IsCompleted)
    {
        Data dataA = null;
        try
        {
            dataA = dataItems.Take();
        }
        catch (InvalidOperationException) { }

        if (dataA != null)
        {
            var dataB = ReadSensorB();
            Process(dataA,dataB);
        }
    }
    Console.WriteLine("\r\nNo more items to take.");
});

// "Thread A"
Task.Run(() =>
{
    while (moreItemsToAdd)
    {
        Data dataA = ReadSensorA();
        dataItems.Add(dataA);
    }
    // Let consumer know we are done.
    dataItems.CompleteAdding();
});

然后moreItemsToAdd就是您需要處理需要關閉此過程的任何代碼。

我不確定你為什么要避免使用任務? 也許你的舊版本.net? 如果是這樣,Damien建議的BlockingCollection也不是一個選擇。 如果您正在使用“普通”線程,則可以使用等待句柄來表示線程之間的結果。 例如, AutoResetEvent

private int a;
private AutoResetEvent newResult = new AutoResetEvent(false);

private void ThreadA()
{
    while (true)
    {
        a = GetSensorA();
        newResult.Set();
    }
}

private void ThreadB()
{
    int b;

    while (true)
    {
        newResult.WaitOne();
        b = GetSensorB();         // or before "waitone"
        Console.WriteLine(a + b); // do something
    }
}

編輯:在重置時有輕微的錯誤,感謝指出Damien - 更新

如果您可以使用.Net 4.5或更高版本,那么解決此問題的最佳方法是使用TPL的DataFlow組件。

(您必須使用NuGet來安裝DataFlow;默認情況下它不是CLR的一部分。)

這是一個示例可編譯控制台應用程序,演示了如何使用DataFlow來執行此操作:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;

namespace SensorDemo
{
    public sealed class SensorAData
    {
        public int Data;
    }

    public sealed class SensorBData
    {
        public double Data;
    }

    public sealed class SensorData
    {
        public SensorAData SensorAData;
        public SensorBData SensorBData;

        public override string ToString()
        {
            return $"SensorAData = {SensorAData.Data}, SensorBData = {SensorBData.Data}";
        }
    }

    class Program
    {
        static void Main()
        {
            var sensorADataSource = new TransformBlock<SensorAData, SensorData>(
                sensorAData => addSensorBData(sensorAData), 
                dataflowOptions());

            var combinedSensorProcessor = new ActionBlock<SensorData>(
                data => process(data), 
                dataflowOptions());

            sensorADataSource.LinkTo(combinedSensorProcessor, new DataflowLinkOptions { PropagateCompletion = true });

            // Create a cancellation source that will cancel after a few seconds.
            var cancellationSource = new CancellationTokenSource(delay:TimeSpan.FromSeconds(20));

            Task.Run(() => continuouslyReadFromSensorA(sensorADataSource, cancellationSource.Token));

            Console.WriteLine("Started reading from SensorA");

            sensorADataSource.Completion.Wait(); // Wait for reading from SensorA to complete.
            Console.WriteLine("Completed reading from SensorA.");

            combinedSensorProcessor.Completion.Wait();
            Console.WriteLine("Completed processing of combined sensor data.");   
        }

        static async Task continuouslyReadFromSensorA(TransformBlock<SensorAData, SensorData> queue, CancellationToken cancellation)
        {
            while (!cancellation.IsCancellationRequested)
                await queue.SendAsync(readSensorAData());

            queue.Complete();
        }

        static SensorData addSensorBData(SensorAData sensorAData)
        {
            return new SensorData
            {
                SensorAData = sensorAData,
                SensorBData = readSensorBData()
            };
        }

        static SensorAData readSensorAData()
        {
            Console.WriteLine("Reading from Sensor A");
            Thread.Sleep(1000); // Simulate reading sensor A data taking some time.
            int value = Interlocked.Increment(ref sensorValue);
            Console.WriteLine("Read Sensor A value = " + value);
            return new SensorAData {Data = value}; 
        }

        static SensorBData readSensorBData()
        {
            Console.WriteLine("Reading from Sensor B");
            Thread.Sleep(100); // Simulate reading sensor B data being much quicker.
            int value = Interlocked.Increment(ref sensorValue);
            Console.WriteLine("Read Sensor B value = " + value);
            return new SensorBData {Data = value};
        }

        static void process(SensorData value)
        {
            Console.WriteLine("Processing sensor data: " + value);
            Thread.Sleep(1000); // Simulate slow processing of combined sensor values.
        }

        static ExecutionDataflowBlockOptions dataflowOptions()
        {
            return new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = 1,
                BoundedCapacity        = 1
            };
        }

        static int sensorValue;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM