我正在开发一个应用程序,我使用特定协议通过 COM 端口将数据包发送到硬件。我有可用的协议规范文档。我可以使用
WriteFile()
发送数据包。通过查看协议规范,我发现我必须每 50 毫秒发送一个特定的数据包。我认为我可以通过让另一个线程每 50 毫秒发送此数据包来实现此目的,以便我可以在主线程中执行其他读/写操作。但是,当我尝试此操作时,它不起作用(RS422 适配器上没有 TXD 并且没有打印任何内容,我添加了 cout
以查看该行是否执行)。我发送数据包的唯一方法是应用程序是单线程的。
这是代码:
void sendBootSignal(HANDLE h_Serial, byte packetArr[], DWORD size)
{
DWORD dwWrite = 11;
if (!WriteFile(h_Serial, packetArr, (DWORD)size, &dwWrite, NULL))
{
std::cout << "error while WriteFile" << std::endl;
}
else
{
std::cout << "succesfully send boot packet" << std::endl;
}
}
void bootThread(HANDLE h_Serial, byte packetArr[], DWORD size)
{
while (true)
{
sendBootSignal(h_Serial, packetArr, size);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
}
int main()
{
h_Serial = CreateFile(L"COM3", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (h_Serial == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
std::cout << "Serial Port not found" << std::endl;
}
std::cout << "error while establishing communication" << std::endl;
}
DCB dcbSerialParam = { 0 };
dcbSerialParam.DCBlength = sizeof(dcbSerialParam);
if (!GetCommState(h_Serial, &dcbSerialParam))
{
std::cout << "error when getting comm state" << std::endl;
}
dcbSerialParam.BaudRate = CBR_115200;
dcbSerialParam.ByteSize = 8;
dcbSerialParam.StopBits = ONESTOPBIT;
dcbSerialParam.Parity = NOPARITY;
dcbSerialParam.fDtrControl = DTR_CONTROL_DISABLE;
if (!SetCommState(h_Serial, &dcbSerialParam))
{
std::cout << "error while setting comm state" << std::endl;
}
COMMTIMEOUTS timeout = { 0 };
timeout.ReadIntervalTimeout = 60;
timeout.ReadTotalTimeoutConstant = 60;
timeout.ReadTotalTimeoutMultiplier = 15;
timeout.WriteTotalTimeoutConstant = 60;
timeout.WriteTotalTimeoutMultiplier = 8;
if (!SetCommTimeouts(h_Serial, &timeout))
{
std::cout << "timeout " << std::endl;
}
byte bootPacket[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
bootPacket[0] = 0x10;
bootPacket[1] = 0x00;
bootPacket[2] = 0x80;
bootPacket[3] = 0x00;
bootPacket[4] = 0x48;
bootPacket[5] = 0x00;
bootPacket[6] = 255;
bootPacket[7] = 0x00;
bootPacket[8] = 0x00;
bootPacket[9] = 0x10;
bootPacket[10] = 0x03;
DWORD size = 11;
sizeCalculator(bootPacket, size);
checksumCalculator(bootPacket, size);
std::thread t1(bootThread, h_Serial, bootPacket, size);
while (true)
{
// do other things here
}
CloseHandle(h_Serial);
}
这种做法不正确吗?如果是,解决这个问题的更好方法是什么?
我发现卡住的原因不是因为
WriteFile()
,而是因为std::cout
。最后的问题仍然有意义。如果有人可以评论为什么 sentBootSignal()
的 else 块中的 cout 只是停止应用程序,我将不胜感激。
重新启动 Visual Studio 修复了
cout
问题,但我仍然想知道多线程这个问题。感谢您的回复。
我希望您的代码至少使用互斥锁来保护发送数据。 该示例还展示了一些使用“C”样式数组发送数据的 C++ 样式替代方案
#include <array>
#include <iostream>
#include <mutex>
#include <span>
#include <Windows.h>
class YourDevice
{
public:
YourDevice()
{
// open serial port etc...
}
~YourDevice()
{
// close serial port etc...
}
// send a packet of N bytes
// Note I use std::uint8_t instead of char to avoid confusion with strings (and signedness)
// used when size is know at compile time
template<DWORD N>
void sendPacket(const std::uint8_t(&packet)[N])
{
// ensure only one thread can send a packet at a time
std::scoped_lock lock(m_mtx);
DWORD dwWrite = N;
if (!WriteFile(m_serial, packet, N, &dwWrite, NULL))
{
std::cout << "error while WriteFile" << std::endl;
}
else
{
std::cout << "succesfully send boot packet" << std::endl;
}
}
// used when size is only known at runtime
void SendPacket(std::span<int> packet)
{
// ensure only one thread can send a packet at a time
std::scoped_lock lock(m_mtx);
DWORD dwWrite = packet.size();
if (!WriteFile(m_serial, packet.data(), packet.size(), &dwWrite, NULL))
{
std::cout << "error while WriteFile" << std::endl;
}
else
{
std::cout << "succesfully send boot packet" << std::endl;
}
}
void sendBootSignal()
{
// the packed is a sequence of 11 bytes initialized with the values provided within the curly braces
sendPacket({0x10, 0x00, 0x80, 0x00, 0x48, 0x00, 0xFF, 0x00, 0x00, 0x10, 0x03});
}
private:
std::mutex m_mtx;
HANDLE m_serial;
};
int main()
{
YourDevice device;
device.sendBootSignal();
}