简体   繁体   English

等待方法完成 C#

[英]Wait for method to be finished C#

I'm communication with an external device (PLC) and he requests data.我正在与外部设备 (PLC) 通信,他请求数据。

I have an event that checks when a value changes in my PLC (for example "NeedNewPosition" or "NeedNewBarValues" )我有一个事件可以检查我的 PLC 中的值何时发生变化(例如"NeedNewPosition""NeedNewBarValues"

I would like to change my code that it will handle them one by one.我想更改我的代码,它将一个一个地处理它们。 Sometimes it seems he's handling 2 of them at the same time.有时他似乎同时在处理其中的两个。 (probably since one takes longer than the other to finish) I've read something about async methods and wait/tasks etc, but that seems a lot of work for something this simple. (可能因为一个比另一个需要更长的时间才能完成)我已经阅读了一些关于异步方法和等待/任务等的内容,但是对于这么简单的事情来说这似乎需要很多工作。

The code:代码:

private void PLCValueChanged(object sender, EventArgs e)
{
    bool xDisplayValue = false;
    PLCVar plcvariable = (PLCVar)sender;
    string VarName = plcvariable.DisplayName;

    switch (VarName)
    {
        case "NEEDNEWPOSITION": //Writing required position to PLC
        if (Convert.ToBoolean(plcvariable.Value))
        {
            SearchNewPosition();
            OPCclient.SendVarToPLC(OPCclient.SendPlcAllBarsFinished, "FALSE");
            OPCclient.SendVarToPLC(OPCclient.SendPLCAllMagnetsFinished, "FALSE");

            MagnetsInArea = GetMagnetsInWorkArea();
            SymbolsInArea = GetSymbolsInWorkArea();
            BarsInArea = GetBarsInWorkArea();
        }
        else
        {
            OPCclient.SendVarToPLC(OPCclient.SendPLCNewPositionIsSend, "FALSE");
        }
        break;

        case "NEEDNEWBARVALUES": //Writing Bar Values to PLC
        if (Convert.ToBoolean(plcvariable.Value))
        {
            OPCclient.SendVarToPLC(OPCclient.SendPLCBarStrippedOK, "FALSE");
            OPCclient.SendVarToPLC(OPCclient.SendPLCBarMagnetsOK, "FALSE");
            OPCclient.SendVarToPLC(OPCclient.SendPLCAllBarMagnetsLoose, "FALSE");

            SetFirstBarValues();

            OffsetsCalculated = false;

            StartVisualisation?.Invoke(this, null); //%M59
        }
        else //if (!Convert.ToBoolean(plcvariable.Value))
        {
            OPCclient.SendVarToPLC(OPCclient.SendPLCBarDataIsSend, "FALSE");
        }
        break;

It sounds like you are looking for a Semaphore .听起来您正在寻找Semaphore Like the like/wiki says:就像喜欢/维基说的:

a semaphore is a variable or abstract data type used to control access to a common resource by multiple threads and avoid critical section problems in a concurrent system such as a multitasking operating system.信号量是一种变量或抽象数据类型,用于控制多个线程对公共资源的访问,并避免并发系统(如多任务操作系统)中的临界区问题。

Ie you can use the semaphore to "block" until a resource becomes available again.即,您可以使用信号量“阻塞”,直到资源再次可用。

You have multiple types of semaphores in C#, but the simplest to use is the SemaphoreSlim . C# 中有多种类型的信号量,但最简单的使用是SemaphoreSlim

You can just define a static one for your singleton class instance您可以为您的 singleton class 实例定义一个 static

private static readonly SemaphoreSlim _semaphore = new(1, 1);

The 1,1 means: "1 is available, and there can only be 1". 1,1表示:“1 可用,并且只能有 1”。

Then in your code:然后在您的代码中:

// take a semaphore, or wait until it is available
await _semaphore.WaitAsync(Timeout.Infinite, cancellationToken);
try
{
    [.. your work...]
}
finally
{
    // give the semaphore back
    _semaphore.Release();
}

Note, I'm using await here, because this means the thread becomes available for other tasks.注意,我在这里使用await ,因为这意味着线程可以用于其他任务。 It will also wait indefinitely until a semaphore is available.它还将无限期地等待,直到信号量可用。 The way to stop this is the cancallationToken .阻止这种情况的方法是cancallationToken

You could wait for the processing of the first event to be finished using an AutoResetEvent :您可以使用AutoResetEvent等待第一个事件的处理完成:

using System.Threading;
// ...

// declare lock as a static class member
private static AutoResetEvent barsInAreaLoaded = new AutoResetEvent(false);

private void PLCValueChanged(object sender, EventArgs e)
{
    // ...

    switch (VarName)
    {
        case "NEEDNEWPOSITION":
        if (Convert.ToBoolean(plcvariable.Value))
        {
            // ...
            BarsInArea = GetBarsInWorkArea();
            // signal waiting thread that bars are ready
            barsInAreaLoaded.Set();
        }
        // ...
        break;

        case "NEEDNEWBARVALUES":
        if (Convert.ToBoolean(plcvariable.Value))
        {
            // ...
            
            // block until bars are ready
            barsInAreaLoaded.WaitOne();
            SetFirstBarValues();
            
            // ...
        }
        // ...
        break;

Note that this will only work if you are sure that the processing of two corresponding NEEDNEWPOSITION and NEEDNEWBARVALUES messages overlap.请注意,这仅在您确定两个相应的NEEDNEWPOSITIONNEEDNEWBARVALUES消息的处理重叠时才有效。 If some of those messages actually pile up this won't solve your problem and you should consider implementing some kind of message queue/pipeline.如果其中一些消息实际上堆积起来,这不会解决您的问题,您应该考虑实施某种消息队列/管道。

Not sure if it can solve your question, i am not expert in PLC but about async method is pretty simple to implement.不确定它是否可以解决您的问题,我不是 PLC 专家,但异步方法很容易实现。

I suggest a simple example for the async part.我建议异步部分的一个简单示例。 Of course is not complete and i suggest you to check out the MSDN page anyway:当然不完整,我建议您还是查看MSDN 页面

  1. declare the function as: private async void...将 function 声明为: private async void...

  2. run an async function like:运行异步 function ,如:

await Task.Run(() => 
{
  // code to run async here 
});

Statement await is one you are looking for (probably)!声明await是您正在寻找的(可能)!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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