Code sample: Suspending and waking up of ACThread


C# public

public class MyWorkerComp : PAClassAlarmingBase
{
    protected SyncQueueEvents _SyncEvent;
    private ACThread _WorkCycleThread;
    public MyWorkerComp(ACClass acType, IACObject content, IACObject parentACObject, ACValueList parameter, string acIdentifier = "")
        : base(acType, content, parentACObject, parameter, acIdentifier)
    {
        // 1. Use ManualResetEvent as a thread synchronization element for shutting down a thread
        _SyncEvent = new SyncQueueEvents();
        // 2. Create a new thread-instance
        _WorkCycleThread = new ACThread(RunWorkCycle);
    }

    public override bool ACInit(Global.ACStartTypes startChildMode = Global.ACStartTypes.Automatic)
    {
        bool result = base.ACInit(startChildMode);
        // 3. Name-Property should contain a unique Identifier. e.g. with a ACUrl:
        _WorkCycleThread.Name = "ACUrl:" + this.GetACUrl() + ";RunWorkCycle();";
        _WorkCycleThread.Start();
        return result;
    }

    public override bool ACDeInit(bool deleteACClassTask = false)
    {
        bool result = base.ACDeInit(deleteACClassTask);

        if (_WorkCycleThread != null)
        {
            // 10. Wakes up thread for executing DoSomething()
            // and stops the loop inside RunWorkCycle() afterwards
            _SyncEvent.TerminateThread();

            // 12. The Join-Method waits until RunWorkCycle()-Method has breaked its loop and ThreadTerminated() was invoked.
            _WorkCycleThread.Join();
            _WorkCycleThread = null;
            _SyncEvent = null;
        }

        return result;
    }

    private void RunWorkCycle()
    {
        try
        {
            // 4. Make a endless loop that only breaks if TerminateThread()-Signal is set from ACDeInit.
            while (!_SyncEvent.ExitThreadEvent.WaitOne(0, false))
            {
                // 5. Suspend this thread and wait for wakeup from ActivateThreadForDoSomething() or from TerminateThread().
                _SyncEvent.NewItemEvent.WaitOne();

                // 7. Call this method for measuring the execution time of your custom code.
                // It's used by the PerformanceLogger-Class that reports statistics to the RuntimeDump-Class.
                _WorkCycleThread.StartReportingExeTime();

                // 8. Invoke your custom code
                DoSomething();

                // 9. Stop Measuring the execution time of this thread.
                _WorkCycleThread.StopReportingExeTime();
            }
        }
        catch (ThreadAbortException e)
        {
            Messages.LogException(this.GetACUrl(), "RunWorkCycle()", e);
        }
        // 11. Report ACDeInit
        _SyncEvent.ThreadTerminated();
    }

    private void DoSomething() { }

    public void ActivateThreadForDoSomething()
    {
        if (!_SyncEvent.NewItemsEnqueueable)
            return;

        // 6. Wakeup thread for executing DoSomething() 
        _SyncEvent.NewItemEvent.Set();
    }
}

Modifier: Aleksandar Agincic / Modified:25.01.2021 10:51