Multi-threading

The sample explains how to create two threads that access a PLC at different time intervals.

Download: sample15-c-ads-dll-multithreading.zip

 

Multi-threading 1:

Multi-threading application with ADS functionalities

Use the extended ADS methods if you want to develop a multi-threading application with ADS functionalities.

#include <iostream>
#include <windows.h>
#include <conio.h>

// ADS headers
#include "c:\twincat\adsapi\tcadsdll\include\tcadsdef.h"
#include "c:\twincat\adsapi\tcadsdll\include\tcadsapi.h"

using namespace std;

DWORD WINAPI ThreadFunction1(LPVOID parameter)
{
    long        nErr, nPort; 
    AmsAddr     Addr; 
    PAmsAddr    pAddr = &Addr; 
    ULONG       lHdlVar, nData;
    ULONG       cbReturn = 0;
    bool        bRun = true;
    char        szVar []={"MAIN.PLCVarRTS1"};

    // Open communication port on local ADS router
    // Use the ADS-Ex-Methods if you implement multi threading

    nPort = AdsPortOpenEx();
    nErr = AdsGetLocalAddressEx(nPort, pAddr);
    if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
    
    // TwinCAT2 RTS1 Port
    pAddr->port = 801;

    // Get the handle of the PLC-variable  
    nErr = AdsSyncReadWriteReqEx2(nPort, pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar, &cbReturn);
    if (nErr) cerr << "Error: AdsSyncReadWriteReq: " << nErr << '\n';

    while(bRun)
    {
        
        DWORD wait = 0;
        
        // Wait 100ms for stopEvent 
        wait = WaitForSingleObject(parameter, 100);

        // If timeout elapse read plc data
        if(WAIT_TIMEOUT == wait)
        {
            // Read the value of a PLC-variable, via handle 
            nErr = AdsSyncReadReqEx2(nPort, pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(nData), &nData, &cbReturn); 
            if (nErr) cerr << "Error: AdsSyncReadReq: " << nErr << '\n'; 
            else cout << "Actual thread --> Thread1 Value: " << nData << '\n'; 
            cout.flush();
        }
        
        else
        {
            bRun = false;
        }
    }

    // Release the handle of the PLC-variable
    nErr = AdsSyncWriteReqEx(nPort, pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar); 
    if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';

    // Close the communication port
    nErr = AdsPortCloseEx(nPort); 
    if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';

    return 1;
}

DWORD WINAPI ThreadFunction2(LPVOID parameter)
{
    long        nErr, nPort; 
    AmsAddr     Addr; 
    PAmsAddr    pAddr = &Addr; 
    ULONG       lHdlVar, nData;
    ULONG       cbReturn = 0;
    bool        bRun = true;
    char        szVar []={"MAIN.PLCVarRTS2"};

    // Open communication port on the local ADS router
    // Use the ADS-Ex-Methods if you implement multi threading and open an additional port

    nPort = AdsPortOpenEx();
    nErr = AdsGetLocalAddressEx(nPort, pAddr);
    if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
    
    // TwinCAT2 RTS1 Port
    pAddr->port = 801;

    // Get the handle of the PLC-variable  
    nErr = AdsSyncReadWriteReqEx2(nPort, pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar, &cbReturn);
    if (nErr) cerr << "Error: AdsSyncReadWriteReq: " << nErr << '\n';

    while(bRun)
    {
        DWORD wait = 0;
        
        // Wait 500ms for stopEvent 
        wait = WaitForSingleObject(parameter, 500);

        // If timeout elapse read plc data
        if(WAIT_TIMEOUT == wait)
        {
            // Read the value of a PLC-variable, via handle 
            nErr = AdsSyncReadReqEx2(nPort, pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(nData), &nData, &cbReturn); 
            if (nErr) 
                cerr << "Error: AdsSyncReadReq: " << nErr << '\n'; 
            else 
                cout << "Actual thread --> Thread2 Value: " << nData << '\n'; 
            cout.flush();
        }           
        
        else
        {
            bRun = false;
        }
    }

    // Release the handle of the PLC-variable
    nErr = AdsSyncWriteReqEx(nPort, pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar); 
    if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';

    // Close the communication port
    nErr = AdsPortCloseEx(nPort); 
    if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';

    return 1;
}

void main()
{
    // StopEvents are used to end the threads
    HANDLE hStopThread1 = CreateEvent(0, FALSE, FALSE, "StopEvent1");
    HANDLE hStopThread2 = CreateEvent(0, FALSE, FALSE, "StopEvent2");

    DWORD threadId1 = 1;
    DWORD threadId2 = 2;

    // Thread creation
    HANDLE hThread1 = CreateThread(0,               // no security
                0,              // default stack size
                ThreadFunction1,
                (void*)hStopThread1,    // parameter
                0,              // creation flags
                &threadId1          // threadId
                );

    HANDLE hThread2 = CreateThread(0,               // no security
                0,              // default stack size
                ThreadFunction2,
                (void*)hStopThread2,    // parameter
                0,              // creation flags
                &threadId2          // threadId
                );
    
    // Loop only for demonstration
    for(int i = 0; i < 10; ++i)
    {
        cout << "Actual thread --> Main Thread" << '\n';
        Sleep(1000);
    }

    // Stop threads
    SetEvent(hStopThread1);
    SetEvent(hStopThread2);
    cout << "Press key to exit: ";
    _getch();
}