Я пытаюсь установить связь с одним и тем же портом, используя два разных потока в программе CLI C ++ (работающей в Windows, но не использующей Windows API). Порт является портом USB (который ведет к преобразователю в RS-232, а затем к другому устройству). Я могу успешно установить порт связи в моем main
используя поток OpenCom()
а также Transmit()
, функции, предоставляемые в DLL производителем этих устройств.
Я тогда звоню newThreadFunc()
(определено в другой DLL), который выполняется в отдельном потоке (назовем его нить обратного вызова) и вызывает функцию обратного вызова. В этой функции обратного вызова я вызываю Transmit()
снова, но теперь он возвращается с ошибкой (определенной DLL): «Порт не готов (CreateFile)».
Вот упрощенный псевдокод:
#include "Device.h" // contains OpenCom() & Transmit()
const short comPort = 3; // COM port number (global)
int main(int argc, char* argv[]) {
OpenCom(comPort); // Open the port
Transmit(command); // where "command" represents some command
newThreadFunc(taskHandle); // Creates new "callback thread" and calls callbackFunc
getchar(); // wait while other thread runs
return 0;
}
signed long __cdecl callbackFunc (params) {
Transmit(command); // error: "Port not ready (CreateFile)"OpenCom(comPort); // error: "Port already open (CreateFile)"}
Если я позвоню OpenCom
в потоке обратного вызова я получаю эту ошибку: «Порт уже открыт (CreateFile)». Таким образом, поток обратного вызова может видеть, что порт открыт, но не может обмениваться данными по нему. Я знаю, что должен каким-то образом управлять связью через порт с мьютексом или чем-то подобным, но в чем причина, почему поток обратного вызова не может обмениваться данными через порт? И как я могу разрешить потоку обратного вызова общаться с портом, который я открыл в основном потоке?
Последовательные порты очень простые устройства, они просто поддерживают непрозрачный поток байтов. Нет протокола, позволяющего двум потокам или двум приложениям совместно использовать порт. Ничего подобного TCP, который позволяет логическое соединение с определенным номером порта через одно сетевое соединение. в Модель OSI, последовательный порт занимает нижний, физический уровень. Не имея стандартов, которые когда-либо появлялись для создания слоев поверх него, никто никогда не соглашался с тем, как должен выглядеть слой № 2. Протокол Hayes AT для модемов настолько далёкий, насколько это возможно.
Так что, если ОС действительно позволит вам сделать это, результат будет очень плохим. Одно приложение или поток украдут данные, предназначенные для другого, которые никогда не могут быть успешно завершены. Так ты действительно делать придется позаботиться об этом самостоятельно и открыть порт один раз. С какой-то схемой для арбитража доступа к порту, который определяет, какой поток получает входные данные. Как мьютекс. Или созданный вами сетевой уровень с логическим адресом назначения, что очень часто встречается в шинных протоколах. Это может быть так же просто, как один байт в сообщении. Но, конечно, добавление требования о том, чтобы вы реализовали канальный уровень и указали формат кадра сообщения, чтобы этот байт мог надежно считываться. Также очень распространено, каждый раскручивает свои собственные.
Других решений пока нет …