2014-09-19 2 views
5

Я успешно включил функцию UDPreceive в свое приложение. ОДНАКО! Я не могу понять, как остановить прослушиватель UDP из бесконечного запуска. Библиотека OSCPack имеет встроенные в нее функции Break() и AsynchronousBreak(), но я не смог их реализовать.C++ Прерывание прослушивателя UDP. Скомпилированный с использованием oscpack в Xcode

в файле udpSocket.cpp в oscpack:

void Run() //the listener function (WORKING!) 
{ 
    break_ = false; 
    //UDP Listener Code 

    void Break() 
    { 
     break_ = true; 
    } 
    void AsynchronousBreak() 
    { 
     break_ = true; 
     // Send a termination message to the asynchronous break pipe, so select() will return 
     write(breakPipe_[1], "!", 1); 
    } 
} 

Моя попытка вызова Break() из класса пакета Слушатель не появляется ничего делать, несмотря на компилятором предполагая, что все называют правильно :

SocketReceiveMultiplexer s; 
s.Break(); 

Другой метод, который я попытался было поднять флаг прерывания в соответствии с функцией RunUntilSigInt(). В классе пакета слушатель:

raise(SIGINT); 

, но это завершает всю программу, а не только разрыв с UDPListener. Для справки, здесь RunUntilSigInt (код) в udpSocket.cpp:

void SocketReceiveMultiplexer::RunUntilSigInt() 
{ 
    assert(multiplexerInstanceToAbortWithSigInt_ == 0); /* at present we support only one multiplexer instance running until sig int */ 
    multiplexerInstanceToAbortWithSigInt_ = this; 
    signal(SIGINT, InterruptSignalHandler); 
    impl_->Run(); 
    signal(SIGINT, SIG_DFL); 
    multiplexerInstanceToAbortWithSigInt_ = 0; 
} 

я полностью застрял на этом, любая помощь/совет будет весьма признателен.

Спасибо, Том

+0

Отправить «дейтаграмму« стоп »локально? –

+0

@MartinJames, спасибо за это, что-то вроде этого? http://stackoverflow.com/questions/4670664/interrupt-a-thread-in-datagramsocket-receive –

ответ

4

Я знаю, что это несколько старый вопрос, но мне пришлось преодолеть это недавно и не нашли хорошего ответа в Интернете. Модель, используемая oscpack, кажется, что они управляют бесконечным циклом Run, и вы реализуете все, что хотите сделать внутри класса, полученного из OscPacketListener. Если вы не хотите так поступать, вам нужно запустить цикл Run в отдельном потоке. Кажется, в версии oscpack 1.1.0 больше нет внутренней поддержки для потоковой обработки. Они объясняют в файле CHANGES для этой версии, что вам нужно будет реализовать свое собственное решение для потоковой передачи. Процедура Run в SocketReceiveMultiplexer никогда не возвращается, поэтому любой код после этого вызова недоступен. Различные подпрограммы Break предназначены для управления выполнением цикла Run из другого потока. В приведенном ниже примере я использую C++ 11 <threads>, но вы можете использовать любую библиотеку потоков, которую вы выбираете для достижения чего-то подобного. В моем примере вам понадобится

#include <threads> 
#include <mutex> 

и скомпилировать ваш код с помощью компилятора C++ 11. В g ++ вам понадобится аргумент командной строки -std=c++11.

Если вы начинаете с receiver example (разбор отдельных сообщений, например) в SVN, вы можете изменить функцию main() быть что-то вроде

void ListnerThread() 
{ 
    PacketListener listener; 
    UdpListeningReceiveSocket s(
      IpEndpointName(IpEndpointName::ANY_ADDRESS, PORT), 
      &listener); 
    s.Run(); 
} 

Где-то еще в вашем коде, сделать вызов, как

std::thread lt(ListnerThread); 

, чтобы запустить прослушиватель. Вам нужно будет создать некоторые способы обмена информацией между вашим основным потоком и потоком слушателя.Один простой метод - использовать глобальную переменную, окруженную мьютексом (также глобальным). Есть, конечно, другие (лучше?) Способы, но это очень легко. Объявите это в глобальном масштабе (следуя их примеру), а в ProcessMessage функции:

std::mutex oscMutex; 

bool a1; 
osc::int32 a2; 
float a3; 
const char *a4; 

Внутри ExamplePacketListener, где они устанавливают переменные из args потока, а затем сделать вызов cout вы могли бы сделать что-то вроде

oscMutex.lock(); 
args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage; 
oscMutex.unlock(); 

Просто убедитесь, что также lock() и unlock() мьютекс таким же образом, где бы вы ни попали к этим переменным в другом месте вашего кода.

+0

Матт, спасибо за указатели! Я решил, что это нужно запускать в другом потоке, но не удалось реализовать это в iOS. Я снова буду работать над этим проектом в 2015 году, поэтому у меня будет время попробовать свой метод. Привет, Том. –

+0

Привет. Поскольку у меня есть собственный основной цикл, есть ли другой способ включить osc :: UdpSocket :: ReceiveFrom() в мой основной цикл? – nass

0

Извините за глупый вопрос: вы пытаетесь запустить слушателя до разрыва?

SocketReceiveMultiplexer s; 
s.Run(); // let wire up the things 
s.Break(); 
+0

Привет, Юрий, Да, слушатель Run() из моей основной программы. Как я уже упоминал выше, код работает отлично ... кроме того, что я не могу сломаться от слушателя и возобновить работу с другими задачами !!! Спасибо, Том. –

2

Это старый, но это единственная страница в Интернете об этой проблеме. В случае, если кому-то нужен oit

Использование raise(SIGINT), когда я запускаю слушателя с помощью функции RunUntilSigInt(), делает трюк для меня. Это быстрый хак и это некрасиво, но это выглядит следующим образом:

 if (std::strcmp(m.AddressPattern(), "/test1") == 0) { 

      osc::ReceivedMessageArgumentStream args = m.ArgumentStream(); 

      osc::int32 a1, a2, a3; 
      const char *a4; 
      args >> a1 >> a2 >> a3 >> a4 >> osc::EndMessage; 

      raise(SIGINT); 
     } 

В этом случае, я остановить слушатель, когда я получаю один пакет, но вы можете изменить его, как вы хотите.

Смежные вопросы