Could I use one common ModbusTcpMaster for multi-thread sending diffrent requests ? Would these threads be blocked ?
MengMengDaXiaoJi opened this issue · comments
Jack Huang commented
My step is like this.
- create a common ModbusTcpMaster instance.
public CompletableFuture<ModbusTcpMaster> createModbusConnector(String ipAddr, int port) {
if (modbusMaster == null) {
ModbusTcpMasterConfig masterConfig = new ModbusTcpMasterConfig.Builder(ipAddr).setPort(port).setTimeout(Duration.parse(TIMEOUT_DURATION)).build();
modbusMaster = new ModbusTcpMaster(masterConfig);
}
return modbusMaster.connect();
}
- then invoke collectModbusData for multi-thread
public CompletableFuture<Boolean> collectModbusData(ModbusNetworkAddress address, ModbusParamWrapper paramWrapper) throws ExecutionException, InterruptedException, TimeoutException {
List<CompletableFuture<Boolean>> futureList = new ArrayList<>();
ModbusMasterUtil modbusMasterUtil = new ModbusMasterUtil();
modbusMasterUtil.createModbusConnector(address.getIpAddr(), address.getPort());
futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getCoilParamSet(), ModbusParam.CODE_READ_COIL));
futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getDiscreteInputParamSet(), ModbusParam.CODE_READ_DISCRETE_INPUT));
futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getHoldingRegisterParamSet(), ModbusParam.CODE_READ_HOLDING_REGISTER));
futureList.add(collectModbusData(modbusMasterUtil, paramWrapper.getInputRegisterParamSet(), ModbusParam.CODE_READ_INPUT_REGISTER));
CompletableFuture<Boolean> future = matchFutureList(futureList);
// future.whenCompleteAsync((result, throwable) -> {
// modbusMasterUtil.disposeModbusConnector();
// if (throwable != null) {
// future.completeExceptionally(throwable);
// }
// });
return future;
}
- collectModbusData function will create a supplyAsync process use customized thread pool "modbusExecutor".
public CompletableFuture<Boolean> collectModbusData(ModbusMasterUtil modbusMasterUtil, ModbusParam modbusParam, int code) {
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
CompletableFuture<int[]> registerFuture = null;
switch (code) {
case ModbusParam.CODE_READ_COIL:
registerFuture = modbusMasterUtil.readCoils(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
break;
case ModbusParam.CODE_READ_DISCRETE_INPUT:
registerFuture = modbusMasterUtil.readDiscreteInputs(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
break;
case ModbusParam.CODE_READ_HOLDING_REGISTER:
registerFuture = modbusMasterUtil.readHoldingRegisters(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
break;
case ModbusParam.CODE_READ_INPUT_REGISTER:
registerFuture = modbusMasterUtil.readInputRegisters(modbusParam.getSlaveId(), modbusParam.getAddress(), modbusParam.getQuantity());
break;
default:
break;
}
if (registerFuture != null) {
try {
int[] registerValues = registerFuture.get();
if (registerValues != null && registerValues.length > 0) {
modbusParam.setRegisterValues(registerValues);
return true;
} else {
return false;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
} else {
return false;
}
}, modbusExecutor);
return future;
}
- finally, they will invoke into ModbusMasterUtil class and sendRequest.
public CompletableFuture<int[]> readCoils(int slaveId, int address, int quantity) {
CompletableFuture<ReadCoilsResponse> futureResponse = modbusMaster.sendRequest(new ReadCoilsRequest(address, quantity),
slaveId);
return futureResponse.thenApply(response -> {
ByteBuf byteBuf = response.getCoilStatus();
int[] values = new int[quantity];
int minimum = Math.min(quantity, byteBuf.capacity() * 8);
for (int i = 0; i < minimum; i += 8) {
setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
}
ReferenceCountUtil.release(response);
return values;
});
}
public CompletableFuture<int[]> readDiscreteInputs(int slaveId, int address, int quantity) {
CompletableFuture<ReadDiscreteInputsResponse> futureResponse = modbusMaster.sendRequest(new ReadDiscreteInputsRequest(address, quantity),
slaveId);
return futureResponse.thenApply(response -> {
ByteBuf byteBuf = response.getInputStatus();
int[] values = new int[quantity];
int minimum = Math.min(quantity, byteBuf.capacity() * 8);
for (int i = 0; i < minimum; i += 8) {
setBooleanArray(byteBuf.readUnsignedByte(), values, i, Math.min(minimum - i, 8));
}
ReferenceCountUtil.release(response);
return values;
});
}
public CompletableFuture<int[]> readHoldingRegisters(int slaveId, int address, int quantity) {
CompletableFuture<ReadHoldingRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadHoldingRegistersRequest(address, quantity),
slaveId);
return futureResponse.thenApply(response -> {
ByteBuf byteBuf = response.getRegisters();
int[] values = new int[quantity];
for (int i = 0; i < byteBuf.capacity() / 2; i++) {
values[i] = byteBuf.readUnsignedShort();
}
ReferenceCountUtil.release(response);
return values;
});
}
public CompletableFuture<int[]> readInputRegisters(int slaveId, int address, int quantity) {
CompletableFuture<ReadInputRegistersResponse> futureResponse = modbusMaster.sendRequest(new ReadInputRegistersRequest(address, quantity),
slaveId);
return futureResponse.thenApply(response -> {
ByteBuf byteBuf = response.getRegisters();
int[] values = new int[quantity];
for (int i = 0; i < byteBuf.capacity() / 2; i++) {
values[i] = byteBuf.readUnsignedShort();
}
ReferenceCountUtil.release(response);
return values;
});
}
Kevin Herron commented
The Master instance is thread safe.
Jack Huang commented
Thanks for your kind help.
The Master instance is thread safe.