用于了解何时可以在新线程中调用方法的模式

时间:2012-02-01 20:20:07

标签: c# multithreading design-patterns

我有一个Device界面:

public interface IDevice
{
    double Measure();
}

实现该界面的一些类具有测量工具:

public class InstrumentedDevice : IDevice
{
    public MeasuringInstrument Instrument { get; set; }

    public double Measure()
    {
        if (Instrument != null)
            return Instrument.DoMeasuring();
        return 0;
    }
}

我想根据InstrumentedDevice属性对Instrument的实例进行分组,以便结果是一组组合,其中每个设备使用与其中所有其他设备相同的工具基。

然后,我想为每个组开始一个新线程并同时执行测量。

这看起来像这样:

public void MeasureAllDevices(IEnumerable<InstrumentedDevice> devices)
{
    var groups = devices.GroupBy(d => d.Instrument);
    foreach (var gr in groups)
    {
        var bgw = new BackgroundWorker();
        bgw.DoWork += (s, e) =>
        {
            foreach (var device in gr)
            {
                device.Measure();
            }
        };
        bgw.RunWorkerAsync();        
    }
}

问题是我没有将InstrumentedDevice的集合作为MeasureAllDevices的参数。我得到了IDevice

的集合
public void MeasureAllDevices(IEnumerable<IDevice> devices)
{

}

我的问题是:我可以遵循一个模式来解决我的问题吗?并非所有设备都具有MeasuringInstrument,并且某些设备可能有不同的方法来确定它们是否可以并行测量。

我想在IDevice界面添加一些内容,例如CanBeMultiThreadedWith(IDevice other),但我不确定这是如何运作的。

4 个答案:

答案 0 :(得分:1)

public interface IDevice
{
    string GroupBy {get;}
    double Measure();
}

答案 1 :(得分:1)

好的,我的第一个回答误解了这个问题。这是一个新的:

public interface IDevice
{
    double Measure();
    string ConcurrencyGroupName { get; }
}

每个设备都获得一个新的“并发组名称”。惯例是只有具有此名称相同的设备才能并行处理。

所以你.GroupBy ConcurrencyGroupName和foreach组你并行处理它的项目。

这样设备决定是否要并行执行。执行处理的中心代码永远不必修改。

您的InstrumentedDevice类只会返回乐器的名称或其ID ConcurrencyGroupName。其他实现也是可能的。

答案 2 :(得分:0)

您需要将设备拆分为已检测的设备和非设备的设备:

var measurable = devices.OfType<InstrumentedDevice>().ToList();
var notMeasurable = devices.Except(measurable).ToList();

您可以单独处理这两个集。

答案 3 :(得分:0)

public static MeasuringInstrument Instrument(this IDevice device)
{
  if (device is InstrumentedDevice)
  {
    return (device as InstrumentedDevice).Instrument;
  }

  return null;
}


var groups = devices.GroupBy(d => d.Instrument());
foreach (var gr in groups)