SoFunction
Updated on 2025-03-07

C# uses channel to realize communication between Plc asynchronous tasks

Examples of channel communication:

using ConsoleApp2;
using ;
using ;

var queue = new BlockingCollection<Message>(new ConcurrentQueue<Message>());

var opt = new BoundedChannelOptions(10)
{
    FullMode = ,
    SingleReader = true,
    SingleWriter = true,
    Capacity = 100 //Maximum capacity};

// Limitedvar channelTest = <Message>(opt);


//Unlimitedvar channel = <Message>();

var sender1 = SendMessageThreadAsync(, 1);
var sender2 = SendMessageThreadAsync(, 2);
var receiver1 = ReceiveMessageThreadAsync(, 3);
var receiver2 = ReceiveMessageThreadAsync(, 4);
//await sender;
// make sure all messages are received

await (sender1, sender2);

();

await (receiver1, receiver2);

//await receiver;

("Press any key to exit...");
();

async Task SendMessageThreadAsync(ChannelWriter<Message> writer, int id)
{
    for (int i = 0; i < 20; i++)
    {
        await (new Message(id, ()));
        ($"Thread {id} sent {i}");
        await (100);
    }
}

async Task ReceiveMessageThreadAsync(ChannelReader<Message> reader, int id)
{

    //try
    //{
    //    while (!)
    //    {
    //        var message = await ();
    //        ($"Thread {id} received {}");
    //    }
    //}
    //catch (Exception ex)
    //{
    //    ($"Thread {id} channel closed:{}");
    //}

    await foreach (var message in ())
    {
        ($"Thread {id} received {}");
    }
}

record Message(int FromId, string Content);






Transformed into Plc example

record PlcDataMessage  
{  
    public bool IsConnected { get; init; }  
    public DbData DbData { get; init; }  
    // You can add other information that needs to be passed}
// Create a boundless channel to send and receive messagesvar plcDataChannel = <PlcDataMessage>();  
  
// Start a new task to simulate PLC data reading(async () =>  
{  
    var cts = new CancellationTokenSource(); // Assume that you already have a cancel token source    while (!)  
    {  
        try  
        {  
            // ... The code connecting the PLC is omitted, and this part of the logic remains unchanged...  
            if (MyIsConnected)  
            {  
                DbData dbDataTemp = await <DbData>(42, 0);  
  
                // Heartbeat and other operations...  
                // Construct the message and send it to Channel                var message = new PlcDataMessage  
                {  
                    IsConnected = MyIsConnected,  
                    DbData = dbDataTemp  
                };  
                await (message, );  
            }  
  
            // ... Other logic remains the same ...        }  
        catch (Exception ex)  
        {  
            // Handle the exception and reconnect the PLC (if required)            // ...  
  
            // A special message can be sent through the Channel to indicate that the connection has been disconnected or an error has occurred            // This part of the logic is omitted here  
            // Try again after sleeping for a while            await (2000, );  
        }  
    }  
  
    // Notify Channel after completion no more data will be sent    ();  
}, , , );  
  
// Read data in Channel in another task or thread(async () =>  
{  
    await foreach (var message in ())  
    {  
        if ()  
        {  
            lock (lockObj)  
            {  
                // Update dbData, here assuming that dbData is a thread-safe object or structure                dbData.Str_S = .Str_S.Trim();  
                // ... Update other properties ...            }  
            // Process the read data...        }  
        else  
        {  
            // Handle PLC disconnection...        }  
    }  
  
    // Reading is completed, Channel is closed    ("PLC data has been read.");  
}, );  
  
// ... Other codes, such as waiting for all tasks to complete, processing cancellation logic, etc. ...
using System;  
using ;  
using ;  
using ;  
  
// ... Other necessary references and type definitions ...  
// Create a boundless channel to send and receive messagesvar plcDataChannel = <PlcDataMessage>();  
  
// Cancel the token sourcevar cts = new CancellationTokenSource();  
  
// Start a new task to simulate PLC data reading(async () =>  
{  
    Plc s7Plc = null;  
    bool MyIsConnected = false;  
    int errorTimes = 0;  
  
    try  
    {  
        while (!)  
        {  
            if (s7Plc == null || !MyIsConnected)  
            {  
                // Try to connect to the PLC (omit the specific implementation)                // ...  
  
                if (MyIsConnected)  
                {  
                    // Connection is successful, send a successful connection message (if required)                    // ...  
                }  
            }  
            else  
            {  
                try  
                {  
                    // Read PLC data (excluding specific implementations)                    DbData dbDataTemp = await <DbData>(42, 0, );  
  
                    // Heartbeat and other operations...  
                    // Construct the message and send it to Channel                    var message = new PlcDataMessage { IsConnected = MyIsConnected, DbData = dbDataTemp };  
                    await (message, );  
  
                    errorTimes = 0; // Reset the error counter                }  
                catch (Exception ex)  
                {  
                    errorTimes++;  
                    // Handle exceptions (such as logging)                    // ...  
  
                    // After a certain number of errors are reached, close the PLC connection and reset                    if (errorTimes > someThreshold)  
                    {  
                        s7Plc?.Close();  
                        s7Plc = null;  
                        MyIsConnected = false;  
                        // You can choose to send a disconnected message to the Channel                    }  
  
                    // Try again after sleeping for a while                    await (2000, );  
                }  
            }  
  
            // Some delays can be added to reduce the frequency of the cycle            await (somePollingInterval, );  
        }  
    }  
    catch (OperationCanceledException)  
    {  
        // Cancellation is expected and no additional processing is required    }  
    finally  
    {  
        // Make sure to close the PLC connection and Channel writer        s7Plc?.Close();  
        ();  
    }  
}, );  
  
// Read data in Channel in another task or thread(async () =>  
{  
    await foreach (var message in ())  
    {  
        if ()  
        {  
            // Update dbData (here assumes that dbData is a thread-safe object or structure)            // Add appropriate synchronization mechanism as needed            // ...  
  
            // Process the read data...        }  
        else  
        {  
            // Handle PLC disconnection...        }  
    }  
  
    // Reading is completed, Channel is closed    ("PLC data has been read.");  
}, );  
  
// ... Other codes, such as waiting for all tasks to complete, processing cancellation logic, etc. ...  
// Cancel the task at some appropriate moment// ();  
  
// Wait for all tasks to complete (if required

Expand: C# Channel implements inter-thread communication

C# Channel implements inter-thread communication

Synchronous method implementation:

using System;
using ;
using ;
using ;
using ;
using ;
using ;
using ;

namespace ConsoleApp1
{
    public class ChannelDemo
    {
        static Channel<Message> channel1 = <Message>();
        public static void Main2()
        {
            (1);
            (2);
            (3);
            ();
            (3000);
            ();
            ();

            ();
            ();


            ();
        }
        static Thread sender = new Thread(SendMsg);

        static Thread receive1 = new Thread(ReceiveMsg);
        static Thread receive2 = new Thread(ReceiveMsg);

        static void SendMsg(object id)
        {
            for (int i = 0; i < 20; i++)
            {
                if ((new Message((int)id, ())))
                {
                    ($"【Thread{id}】Sent【{i}】");
                }
            }
        }

        static void ReceiveMsg(object id)
        {
            try
            {
                while (true)
                {
                    if ((out Message message))
                    {
                        ($"【Thread{id}】from【Thread{}】Received【{}】");

                    }
                    (1);
                }
            }
            catch (ThreadInterruptedException ex)
            {
                ($"End of Reception");
            }
        }
    }
}


Asynchronous method:

using System;
using ;
using ;
using ;
using ;
using ;
using ;
using ;
using ;

namespace ConsoleApp1
{
    public class ChannelDemo2
    {
        static Channel<Message> channel1 = <Message>();
        
         public static async void Main2()
        {
            await (sender, sender2);
            ();
            await (receive1, receive2);
           
            ();
        }

        static Task sender = SendMsgAsync(, 1);
        static Task sender2 = SendMsgAsync(, 4);
        static Task receive1 = ReceiveMsgAsync(, 2);
        static Task receive2 = ReceiveMsgAsync(, 3);

        static async  Task SendMsgAsync(ChannelWriter<Message> writer, int id)
        {
            for (int i = 0; i < 20; i++)
            {
                await (new Message((int)id, ()));
                ($"【Thread{id}】Sent【{i}】");
            }
        }

        static async Task ReceiveMsgAsync(ChannelReader<Message> reader,int id)
        {
            try
            {
                while (!)
                {
                    Message message = await ();           
                    ($"【Thread{id}】from【Thread{}】Received【{}】");
                   
                }
            }
            catch (ChannelClosedException ex)
            {
                ($"ChannelClosed Received End");
            }
        }

    }
}


When instantiating the Channel, you can also pass an Options, where the message capacity, whether multiple senders and recipients can be defined.

The above is the detailed content of C# using channel to implement communication between Plc asynchronous tasks. For more information about C# channel Plc asynchronous communication, please pay attention to my other related articles!