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 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();
}