简体   繁体   English

是否有线程的await语句?

[英]Is there an await statement for threads?

Hi I would like to know if there is something similiar to the await statement, which is used with tasks, which I can implement with threads in c#? 嗨,我想知道是否有类似await语句的东西,它与任务一起使用,我可以用c#中的线程实现?

What I want to do is: 我想做的是:

Start Thread A, compute some data and put the result on variable x . 启动线程A,计算一些数据并将结果放在变量x After that variable x is transferred to another thread B and at the same time Thread A starts again to compute some data, while thread B starts another calculation with the result x . 之后,变量x被转移到另一个线程B,同时线程A再次开始计算一些数据,而线程B开始另一个计算结果x

UPDATE: Ok there seems to be some confusion so I will be more accurate in my description: 更新:好的,似乎有一些混乱,所以我的描述会更准确:

I use two sensors which produce data. 我使用两个产生数据的传感器。 The data needs to be retrieved in such a way that SensorA data is retrieved (which takes a long time) and immediately after that the data from SensorB must be retrieved in another Thread, while SensorA continues retrieving another data block. 需要以检索SensorA数据的方式检索数据(这需要很长时间),之后必须在另一个线程中检索来自SensorB的数据,而SensorA继续检索另一个数据块。 The problem is i cant queue the data of both sensors in the same queue, but I need to store the data of both sensor in ONE data structure/object. 问题是我不能将两个传感器的数据排队在同一队列中,但我需要将两个传感器的数据存储在一个数据结构/对象中。

My idea was like that: 我的想法是这样的:

  1. Get Data from Sensor A in Thread A. 从线程A中的传感器A获取数据
  2. Give result to Thread B and restart Thread A. 将结果提供给线程B并重新启动线程A.
  3. While Thread A runs again Thread B gets Data from Sensor B and computes the data from Sensor A and B 当线程A再次运行时,线程B从传感器B获取数据并计算来自传感器A和B的数据

You can assume that Thread A always needs a longer time than Thread B 您可以假设线程A总是需要比线程B更长的时间

As I said in a comment. 正如我在评论中所说。 This looks like classic Producer/Consumer, for which we can use eg a BlockingCollection . 这看起来像经典的制作人/消费者,我们可以使用它,例如BlockingCollection

This is a slight modification of the sample from that page: 这是对该页面中的示例的轻微修改:

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

And then moreItemsToAdd is just whatever code you need to have to cope with needing to shut this process down. 然后moreItemsToAdd就是您需要处理需要关闭此过程的任何代码。

I'm not sure why you're avoiding the use of tasks? 我不确定你为什么要避免使用任务? Maybe you're on an older version of .net? 也许你的旧版本.net? If so, BlockingCollection as Damien suggested is also not an option. 如果是这样,Damien建议的BlockingCollection也不是一个选择。 If you're using "normal" threads, you can use a waithandle to signal results between threads. 如果您正在使用“普通”线程,则可以使用等待句柄来表示线程之间的结果。 For example, an AutoResetEvent . 例如, 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
    }
}

edit: had slight mistake in there with the reset, thanks for pointing out Damien - updated 编辑:在重置时有轻微的错误,感谢指出Damien - 更新

If you can use .Net 4.5 or later, then the best way to approach this is to use the DataFlow component of the TPL. 如果您可以使用.Net 4.5或更高版本,那么解决此问题的最佳方法是使用TPL的DataFlow组件。

(You must use NuGet to install DataFlow; it's not part of the CLR by default.) (您必须使用NuGet来安装DataFlow;默认情况下它不是CLR的一部分。)

Here's a sample compilable console application which demonstrates how to use DataFlow to do it: 这是一个示例可编译控制台应用程序,演示了如何使用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