C#如何在多线程应用程序

时间:2015-06-23 09:14:09

标签: c# multithreading plc

我正在编写一个应该模拟PLC行为的应用程序。这意味着我必须运行多个线程,确保一次只有一个线程处于活动状态,所有其他线程都被挂起。 例如:

  • 线程1每130ms重复一次并阻塞所有其他线程。有效运行时间为30毫秒,其他线程可以使用重新启动线程重启前的100毫秒。
  • 线程2每300ms重复一次并阻塞除线程1以外的所有线程。有效运行时间为50ms(其余线程可以使用剩余的250ms)。线程2暂停,直到线程1完成执行代码(线程1的剩余100ms),一旦线程1处于睡眠状态,它将从暂停的位置恢复
  • 线程3每1000ms重复一次。有效运行时间为100毫秒。仅当所有其他线程都被挂起时,此线程才会继续执行。

最高优先级是在再次调用任务之前完成任务,否则我必须做出反应,因此应该阻塞的线程不应该运行到某个点,否则多核处理会详细说明代码而只等待通过结果。

我阅读了几篇帖子,并了解到Thread.suspend不是推荐的,信号量或监视操作意味着代码执行直到代码中的特定和固定点,而我必须暂停线程到达执行时到达的位置调用另一个线程(具有更高的"优先级")。

我还查看了优先级设置,但它似乎没有100%相关,因为系统可以覆盖优先级。

是否有正确或至少可靠的方法来编码阻止机制?

2 个答案:

答案 0 :(得分:1)

我希望我不会错过理解你的问题:)

您的问题的一种可能性可能是使用并发队列:https://msdn.microsoft.com/de-de/library/dd267265(v=vs.110).aspx

例如,您创建一个枚举来控制您的状态并启动队列:

 private ConcurrentQueue<Action> _clientActions ;
     private enum Statuskatalog
      {
           Idle,
           Busy
       };

创建一个计时器以启动并创建一个timerfunktion。

Timer _taskTimer = new Timer(ProcessPendingTasks, null, 100, 333);



private void ProcessPendingTasks(object x)
         {
           _status = Statuskatalog.Busy;
             _taskTimer.Change(Timeout.Infinite, Timeout.Infinite);
             Action currentTask;
             while( _clientActions.TryDequeue( out currentTask ))
             {
                 var task = new Task(currentTask);
                 task.Start();         
                 task.Wait();
             }

         _status=Statuskatalog.Idle;
         }

现在,您只需将任务作为代理添加到队列中:

_clientActions.Enqueue(delegate { **Your task** });
            if (_status == Statuskatalog.Idle) _taskTimer.Change(0, 333);

在此基础上,您可以管理您要求的特殊要求。

希望这是,你在寻找什么。

答案 1 :(得分:1)

我认为你根本不需要给自己增加负担Thread。相反,您可以将Task与优先级TaskScheduler一起使用(通过Google搜索来编写或查找并不难)。

这使代码非常容易编写,例如,最高优先级的线程可能类似于:

while (!cancellationRequested)
{
  var repeatTask = Task.Delay(130);

  // Do your high priority work      

  await repeatTask;
}

您的其他任务将具有类似的基本布局,但在任务调度程序中它们将被赋予较低的优先级(这通常由任务调度程序处理,每个任务优先级具有单独的队列)。偶尔,他们可以检查是否有更高优先级的任务,如果有,他们可以await Task.Yield();。事实上,在你的情况下,你似乎甚至不需要真正的队列 - 这使得这更容易,甚至更好,让你真正有效地使用Task.Yield

最终结果是,所有三个周期性任务都只在一个线程上有效运行(如果它们都在等待,甚至根本就没有线程)。

当然,这确实依赖于合作多任务。实际上不可能像Windows上的抢先一样处理全面实时 - 部分抢占解决方案往往充满了问题。如果您控制了在任务中花费的大部分时间(并使用异步I / O卸载任何其他工作),那么协同解决方案实际上效率更高,并且可以减少延迟(尽管它确实不应该太重要了。