S7NetPlus / s7netplus

S7.NET+ -- A .NET library to connect to Siemens Step7 devices
MIT License
1.34k stars 589 forks source link

S7netplus async reading data #359

Closed midelav closed 3 years ago

midelav commented 3 years ago

Dear all, I am working on a UWP C# project to communicate with PLC S7-300. The driver is s7netplus v0.8.1 I need to read data from 3 different PLCs and also 2-3 DBs from each one. I have written some test functions using ReadClass and it is working fine as long as I am on main thread. If I change the code just like below to run the reading task async, after a while (timer do this job every 500ms), It starts to show some exceptions and the reading process stops. I thing I must have some mistake in the code, here is simple code: How should I change the code? Thanks

`Plc SamplePlc = new Plc(CpuType.S7300, "192.168.2.4", 0, 2); private void btnConnect_Click(object sender, RoutedEventArgs e) { SamplePlc.Open(); Debug.WriteLine($"PLC thread: {Thread.CurrentThread.ManagedThreadId}"); }

    DB5 db5 = new DB5();
    private void btnRead_Click(object sender, RoutedEventArgs e)
    {
        SamplePlc.ReadClass(db5, 5);
        Debug.WriteLine($"Read data thread: {Thread.CurrentThread.ManagedThreadId}");

        Task.Run(async () =>
        {
            SamplePlc.ReadClass(db5, 5);
            Debug.WriteLine($"Read data thread: {Thread.CurrentThread.ManagedThreadId}");
        });
    }`
scamille commented 3 years ago

Make sure you are synchronized per plc object. You cannot access the same (plc, connection) in parallel with the S7 protocol, and S7NetPlus does not automatically take care of it for you.

Either use some locking mechanism, or create a queue from with task from which you only process one at a time, etc.

midelav commented 3 years ago

Either use some locking mechanism, or create a queue from with task from which you only process one at a time, etc.

Thanks for your quick answer, but how can I do this?

Another question is that there is a readAsync function in S7netpuls, how about it? is it helpful in this case?

vladimir-metralight commented 3 years ago

Create one lock object for Plc access: private object _locker = new object();

For every read and every write, use lock block like this:

lock (_locker) {
   SamplePlc.ReadClass(db5, 5);
}

This way only one thread at a time will try to read or write the plc and other threads will wait until the lock is released.

mycroes commented 3 years ago

v0.12.0 now has internal synchronization to avoid concurrency issues.