0

ブースト ライブラリを使用して、非同期 UDP 通信を開発しています。受信側で受信したデータが別のスレッドによって処理されています。次に、私の問題は、受信スレッドではなく別のスレッドで受信データを読み取るときに、本来あるべきデータではない変更されたデータまたは更新されたデータを提供することです。私のコードは、送信側と受信側の符号なし文字バッファー配列で動作しています。その理由は、署名されていない文字バッファーをデータのパケットと見なす必要があるためです。たとえば、buffer[2] = Engine_start_ID

  /* global buffer to store the incomming data 
  unsigned char received_buffer[200];
  /*
     global buffer accessed by another thread
      which contains copy the received_buffer
  */
   unsigned char read_hmi_buffer[200];
   boost::mutex hmi_buffer_copy_mutex;


       void udpComm::start_async_receive() {
             udp_socket.async_receive_from(
             boost::asio::buffer(received_buffer, max_length), remote_endpoint,
             boost::bind(&udpComm::handle_receive_from, this,
             boost::asio::placeholders::error,
             boost::asio::placeholders::bytes_transferred));
      }
   /* the data received is stored in the unsigned char received_buffer data buffer*/

     void udpComm::handle_receive_from(const boost::system::error_code& error,
        size_t bytes_recvd) {
        if (!error && bytes_recvd > 0) {
            received_bytes = bytes_recvd;
                    hmi_buffer_copy_mutex.lock();
             memcpy(&read_hmi_buffer[0], &received_buffer[0], received_bytes);
                     hmi_buffer_copy_mutex.unlock();

                     /*data received here is correct  'cus i printed in the console
                      checked it
                     */
                    cout<<(int)read_hmi_buffer[2]<<endl;
       }

             start_async_receive();

       }
       /*  io_service  is running in a thread 
         */
       void udpComm::run_io_service() {
       udp_io_service.run();
        usleep(1000000);
         }

上記のコードは、スレッドを実行する非同期 udp 通信です。

/* 私の 2 番目のスレッド関数は */

        void  thread_write_to_datalink()
         {    hmi_buffer_copy_mutex.lock();
           /* here is my problem begins*/
              cout<<(int)read_hmi_buffer[2]<<endl;
             hmi_buffer_copy_mutex.unlock();

           /* all data are already changed */

              serial.write_to_serial(read_hmi_buffer, 6);

         }
         /* threads from my main function
          are as below */


           int main() {
                 receive_from_hmi.start_async_receive();
              boost::thread thread_receive_from_hmi(&udpComm::run_io_service,
                &receive_from_hmi);
              boost::thread thread_serial(&thread_write_to_datalink);   
              thread_serial.join();
              thread_receive_from_hmi.join();
                 return 0;
        } 

/* Serial_manager クラスには、シリアルポートから読み書きするための関数が含まれています*/

  #include <iostream>
            #include <boost/thread.hpp>
            #include <boost/asio.hpp>
            #include <boost/date_time/posix_time/posix_time.hpp>


            using namespace boost::asio;

            class Serial_manager {
            public:

                Serial_manager(boost::asio::io_service &serial_io_service,char *dev_name);
                void open_serial_port();
                void write_to_serial(void *data, int size);
                size_t read_from_serial(void *data, int size);
                void handle_serial_exception(std::exception &ex);
                virtual ~Serial_manager();
                void setDeviceName(char* deviceName);

            protected:
                io_service &port_io_service;
                serial_port datalink_serial_port;
                bool serial_port_open;
                char *device_name;

            };

            void Serial_manager::setDeviceName(char* deviceName) {
                device_name = deviceName;
            }
            Serial_manager::Serial_manager(boost::asio::io_service &serial_io_service,char *dev_name):
                port_io_service(serial_io_service),
                datalink_serial_port(serial_io_service) {
                device_name = dev_name;
                serial_port_open = false;
                open_serial_port();
            }

            void Serial_manager::open_serial_port() {
                bool temp_port_status = false;
                bool serial_port_msg_printed = false;
                do {
                    try {
                        datalink_serial_port.open(device_name);
                        temp_port_status = true;
                    } catch (std::exception &ex) {
                        if (!serial_port_msg_printed) {
                            std::cout << "Exception-check the serial port device "
                                    << ex.what() << std::endl;
                            serial_port_msg_printed = true;
                        }
                        datalink_serial_port.close();
                        temp_port_status = false;
                    }

                } while (!temp_port_status);
                serial_port_open = temp_port_status;
                std::cout <<std::endl <<"serial port device opened successfully"<<std::endl;
                datalink_serial_port.set_option(serial_port_base::baud_rate(115200));
                datalink_serial_port.set_option(
                        serial_port_base::flow_control(
                                serial_port_base::flow_control::none));
                datalink_serial_port.set_option(
                        serial_port_base::parity(serial_port_base::parity::none));
                datalink_serial_port.set_option(
                        serial_port_base::stop_bits(serial_port_base::stop_bits::one));
                datalink_serial_port.set_option(serial_port_base::character_size(8));

            }

            void Serial_manager::write_to_serial(void *data, int size) {
                boost::asio::write(datalink_serial_port, boost::asio::buffer(data, size));
            }

            size_t Serial_manager::read_from_serial(void *data, int size) {
                return boost::asio::read(datalink_serial_port, boost::asio::buffer(data, size));
            }
            void Serial_manager::handle_serial_exception(std::exception& ex) {
                std::cout << "Exception-- " << ex.what() << std::endl;
                std::cout << "Cannot access data-link, check the serial connection"
                        << std::endl;
                datalink_serial_port.close();
                open_serial_port();
            }

            Serial_manager::~Serial_manager() {
                // TODO Auto-generated destructor stub
            }

私の問題はスレッドの同期と通知に関するものだと思います。助けていただければ幸いです。データが受信側スレッドで受信されることを既に確認したので、送信側が完全に機能することを心配する必要はありません。私の質問を理解していただければ幸いです。

編集:ここに変更があります。ここでの私の全体的な考えは、手動飛行制御のシミュレーションを開発することです。そのため、私の設計によれば、udp 通信を介してコマンドを送信するクライアント アプリケーションがあります。受信側では、3 つのスレッドを使用することを意図していました。1 つのスレッドはスティックから入力を受け取ります。つまりvoid start_hotas() です。2番目のスレッドは送信者 (クライアント) からコマンドを受け取るスレッドです: void udpComm::run_io_service()で、3 番目は void thread_write_to_datalink()です。

              /* a thread that listens for input from sticks*/
            void start_hotas() {
        Hotas_manager hotasobj;
        __s16 event_value; /* value */
        __u8 event_number; /* axis/button number */
        while (1) {
            hotasobj.readData_from_hotas();


            event_number = hotasobj.getJoystickEvent().number;
            event_value = hotasobj.getJoystickEvent().value;
            if (hotasobj.isAxisPressed()) {
                if (event_number == 0) {
                    aileron = (float) event_value / 32767;

                } else if (event_number == 1) {
                    elevator = -(float) event_value / 32767;

                } else if (event_number == 2) {
                    rudder = (float) event_value / 32767;

                } else if (event_number == 3) {
                    brake_left = (float) (32767 - event_value) /    65534;


                } else if (event_number == 4) {


                } else if (event_number == 6) {


                } else if (event_number == 10) {


                } else if (event_number == 11) {

                } else if (event_number == 12) {



                }
            } else if (hotasobj.isButtonPressed()) {



            }
            usleep(1000);

        }

    }


            /*
     * Hotas.h
     *
     *  Created on: Jan 31, 2013
     *      Author: metec
     */

    #define JOY_DEV  "/dev/input/js0"
    #include <iostream>
    #include <boost/thread.hpp>
    #include <boost/asio.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    #include <linux/joystick.h>

    bool message_printed = false;
    bool message2_printed = false;

    class Hotas_manager {
    public:
        Hotas_manager();
        virtual ~Hotas_manager();
        void open_hotas_device();

        /*
         *
         * read from hotas input
         * used to the updated event data and status of the joystick from the
         * the file.
         *
         */
        void readData_from_hotas();

        js_event getJoystickEvent() {
            return joystick_event;
        }

        int getNumOfAxis() {
            return num_of_axis;
        }

        int getNumOfButtons() {
            return num_of_buttons;
        }

        bool isAxisPressed() {
            return axis_pressed;
        }

        bool isButtonPressed() {
            return button_pressed;
        }

        int* getAxis() {
            return axis;
        }

        char* getButton() {
            return button;
        }

    private:
        int fd;
        js_event joystick_event;
        bool hotas_connected;
        int num_of_axis;
        int num_of_buttons;
        int version;
        char devName[80];

        /*
         * the the variables below indicates
         * the state of the joystick.
         */
        int axis[30];
        char button[30];
        bool button_pressed;
        bool axis_pressed;
    };

    Hotas_manager::Hotas_manager() {
        // TODO Auto-generated constructor stub
        hotas_connected = false;
        open_hotas_device();
        std::cout << "joystick device detected" << std::endl;

    }

    Hotas_manager::~Hotas_manager() {
        // TODO Auto-generated destructor stub

    }

    void Hotas_manager::open_hotas_device() {
        bool file_open_error_printed = false;
        while (!hotas_connected) {
            if ((fd = open(JOY_DEV, O_RDONLY)) > 0) {
                ioctl(fd, JSIOCGAXES, num_of_axis);
                ioctl(fd, JSIOCGBUTTONS, num_of_buttons);
                ioctl(fd, JSIOCGVERSION, version);
                ioctl(fd, JSIOCGNAME(80), devName);
                /*
                 * NON BLOCKING MODE
                 */
                ioctl(fd, F_SETFL, O_NONBLOCK);
                hotas_connected = true;
            } else {
                if (!file_open_error_printed) {
                    std::cout << "hotas device not detected. check "
                            "whether it is "
                            "plugged" << std::endl;
                    file_open_error_printed = true;
                }
                close(fd);
                hotas_connected = false;
            }
        }

    }

    void Hotas_manager::readData_from_hotas() {
        int result;
        result = read(fd, &joystick_event, sizeof(struct js_event));
        if (result > 0) {
            switch (joystick_event.type & ~JS_EVENT_INIT) {
            case JS_EVENT_AXIS:
                axis[joystick_event.number] = joystick_event.value;
                axis_pressed = true;
                button_pressed = false;
                break;
            case JS_EVENT_BUTTON:
                button[joystick_event.number] = joystick_event.value;
                button_pressed = true;
                axis_pressed = false;
                break;
            }
            message2_printed = false;
            message_printed = false;

        } else {
            if (!message_printed) {
                std::cout << "problem in reading the stick file" << std::endl;
                message_printed = true;
            }
            hotas_connected = false;
            open_hotas_device();
            if (!message2_printed) {
                std::cout << "stick re-connected" << std::endl;
                message2_printed = true;
            }

        }

    }



I updated the main function to run 3 threads .




    int main() {


                boost::asio::io_service receive_from_hmi_io;
                udpComm receive_from_hmi(receive_from_hmi_io, 6012);
                receive_from_hmi.setRemoteEndpoint("127.0.0.1", 6011);
                receive_from_hmi.start_async_receive();
                boost::thread thread_receive_from_hmi(&udpComm::run_io_service,
                        &receive_from_hmi);
                boost::thread thread_serial(&thread_write_to_datalink);
                boost::thread thread_hotas(&start_hotas);
                thread_hotas.join();
                thread_serial.join();
                thread_receive_from_hmi.join();
                return 0;
                 }

void thread_write_to_datalink()は 、hotas_manager(ジョイスティック) からのデータも書き込みます。

            void thread_write_to_datalink() {

                /*
                 * boost serial  communication
                 */
                boost::asio::io_service serial_port_io;
                Serial_manager serial(serial_port_io, (char*) "/dev/ttyUSB0");   


                cout << "aileron  " << "throttle   " << "elevator   " << endl;
                while (1) { 

                        // commands from udp communication      

                      serial.write_to_serial(read_hmi_buffer, 6);

                    // data come from joystick inputs

                    //cout << aileron<<"    "<<throttle<<"    "<<elevator<< endl;
                    memcpy(&buffer_manual_flightcontrol[4], &aileron, 4);
                    memcpy(&buffer_manual_flightcontrol[8], &throttle, 4);
                    memcpy(&buffer_manual_flightcontrol[12], &elevator, 4);

                    unsigned char temp;


                    try {
                        serial.write_to_serial(buffer_manual_flightcontrol, 32);
                        //serial.write_to_serial(buffer_manual_flightcontrol, 32);
                    } catch (std::exception& exp) {
                        serial.handle_serial_exception(exp);
                    }

                    try {
                        serial.write_to_serial(buffer_payloadcontrol, 20);
                    } catch (std::exception& exp) {
                        serial.handle_serial_exception(exp);
                    }

                    usleep(100000);

                }

            }

私の質問は、これら 3 つのスレッドを同期させるためにどのように設計すればよいかということです。3 つのスレッドを使用する必要がないという回答が あった場合は、その方法を教えてください。

4

2 に答える 2

0

read_hmi_buffer 同期へのアクセスを作成する必要があります。

したがって、コードの一部がそのバッファーで読み取りまたは書き込みを行うたびにロックするには、ミューテックス ( std::mutexpthread_mutex_t、または Windows に相当するもの) が必要です。

概念に関するいくつかの説明と他のチュートリアルへのリンクについては、この質問を参照してください。

于 2013-03-08T16:09:00.800 に答える
0

マルチスレッドから少し話を戻しましょう。あなたのプログラムでは同期操作と非同期操作が混在しています。混乱を招くだけなので、これを行う必要はありません。UDP ソケットから読み取ったバッファをシリアル ポートに非同期で書き込むことができます。これはすべて、 を実行する 1 つのスレッドで実現できるio_serviceため、同時実行に関する懸念がなくなります。

async_writeソケットから読み取ったデータをシリアル ポートの存続期間中スコープ内に保持するには、バッファ管理を追加する必要があります。例として非同期 UDP サーバーを検討してください。また、ドキュメント、特にバッファーの有効期間の要件についても調べてください。async_write

バッファ

書き込まれるデータを含む 1 つ以上のバッファー。buffers オブジェクトは必要に応じてコピーできますが、基になるメモリ ブロックの所有権は呼び出し元によって保持されます。呼び出し元は、ハンドラーが呼び出されるまでそれらが有効であることを保証する必要があります。

その設計が完了したら、スレッド プールや複数の などのより高度なio_service手法に移行できます。

于 2013-03-12T02:20:27.573 に答える