简体   繁体   English

C ++信号量混乱?

[英]C++ Semaphore Confusion?

So, I'm writing a sort of oscilloscope-esque program that reads the the serial port on the computer and performs an fft on this data to convert it to the frequency spectrum. 因此,我正在编写一种类似示波器的程序,该程序读取计算机上的串行端口并对该数据执行fft,以将其转换为频谱。 I ran into an issue though with the layout of my program which is broken up into a SerialHandler class (utilizing boost::Asio ), an FFTHandler class, and a main function. 我在程序布局上遇到了一个问题,该程序被分解为SerialHandler类(利用boost::Asio ), FFTHandler类和一个main函数。 The SerialHandler class uses the boost::Asio`` async_read_some function to read from the port and raise an event called HandleOnPortReceive which then reads the data itself. SerialHandler类使用boost::Asio`` async_read_some函数从端口读取并引发一个称为HandleOnPortReceive的事件,该事件然后读取数据本身。

The issue was that I couldn't find a way to pass that data from the event handler, being raised by an io_service object on another thread, to the FFTHandler class, which is on yet another thread. 问题是我找不到将事件处理程序中的数据(由另一个线程上的io_service对象引发)传递到另一个线程上的FFTHandler类的方法。 I was recommended to use semaphores to solve my problem, but I have next to no knowledge on semaphore.h usage, so my implementation is now rather broken and doesn't do much of anything it's supposed to. 建议我使用信号量来解决问题,但是我几乎不了解semaphore.h的用法,因此我的实现现在已经很糟糕了,它并没有执行应做的任何事情。

Here's some code if that makes it a little clearer: 如果可以使代码更清晰一些,请看下面的代码:

using namespace Foo;
//main function      
int main(void){
     SerialHandler serialHandler;
     FFTHandler fftHandler;

     sem_t *qSem_ptr = &qSem;

     sem_init(qSem_ptr, 1, 0);

     //create separate threads for both the io_service and the AppendIn so that neither will block the user input statement following
     serialHandler.StartConnection(tempInt, tempString); //these args are defined, but for brevity's sake, I ommitted the declaration

     t2= new boost::thread(boost::bind(&FFTHandler::AppendIn, &fftHandler, q, qSem));

    //allow the user to stop the program and avoid the problem of an infinite loop blocking the program
    char inChar = getchar();
    if (inChar) {...some logic to stop reading}
}




namespace Foo{

    boost::thread *t1;
    boost::thread *t2;
    sem_t qSem;
    std::queue<double> q;
    boost::mutex mutex_;

    class SerialHandler{
    private:
        char *rawBuffer; //array to hold incoming data
        boost::asio::io_service ioService;
        boost::asio::serial_port_ptr serialPort;
    public:

            void SerialHandler::StartConnection(int _baudRate, string _comPort){
                //some functionality to open the port that is irrelevant to the question goes here

                AsyncReadSome();  //starts the read loop

                //create thread for io_service object and let function go out of scope
                t1 = new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService)); 

            }

            void SerialHandler::AsyncReadSome(){

                //there's some other stuff here for error_catching, but this is the only important part
                serialPort->async_read_some (
                            boost::asio::buffer(rawBuffer, SERIAL_PORT_READ_BUF_SIZE),
                            boost::bind(
                                    &SerialHandler::HandlePortOnReceive,
                                    this, boost::asio::placeholders::error,
                                    boost::asio::placeholders::bytes_transferred, q));
           }

           void SerialHandler::HandlePortOnReceive(const boost::system::error_code& error, size_t bytes_transferred, std::queue<double>& q){
                boost::mutex::scoped_lock lock(mutex_);
                 //more error checking goes here, but I've made sure they aren't returning and are not the issue

                 for (unsigned int i =0; i<bytes_transferred; i++){
                    unsigned char c = rawBuffer[i];
                    double d = (double) c;  //loop through buffer and read
                    if (c==endOfLineChar){
                    } else  //if not delimiting char, push into queue and post semaphore
                    {
                            q.push(d);
                            //cout << d  << endl;
                            sem_post(&qSem);
                            cout << q.front() << endl;
                            cout << "size is: " << q.size() << endl;
                    }
                }
                //loop back on itself and start the next read
                AsyncReadSome();

            }
    }

    class FFTHandler{
    private:
        double *in; //array to hold inputs
        fftw_complex *out; //holds outputs
        int currentIndex;
        bool filled;
        const int N;
    public:


        void AppendIn(std::queue<double> &q, sem_t &qSem){
                while(1){  //this is supposed to stop thread from exiting and going out of scope...it doesn't do that at all effectively...
                    cout << "test" << endl;
                    sem_wait(&_qSem); //wait for data...this is blocking but I don't know why
                    double d = _q.front();
                    _q.pop();
                    in[currentIndex]=d; //read queue, pop, then append in array
                    currentIndex++;
                    if (currentIndex == N){ //run FFT if full and reset index
                            currentIndex = N-overlap-1;
                            filled = true;
                            RunFFT();
                    }
                }

         }
    }

}

That debug line in FFTHandler::AppendIn(..) is indeed firing, so the thread is being created, but it's immediateley going out of scope it seems and destructing the thread, because it seems I've set up the while to respond incorrectly to the semaphore. FFTHandler::AppendIn(..)调试行确实正在触发,因此正在创建线程,但是它立即超出了范围并破坏了线程,因为似乎我已经设置了错误响应的时间。到信号量。

TLDR : That was a long explanation to simply say, "I don't understand semaphores but need to somehow implement them. I tried, failed, so now I'm coming here to hopefully receive help on this code from somebody more knowledgeable than me. TLDR :这是一个很长的解释,可以简单地说:“我不理解信号灯,但是需要以某种方式实现它们。我尝试了,但失败了,所以现在我来这里是希望从比我更有知识的人那里获得有关此代码的帮助。 。

UPDATE: So after playing around with some debug statements, it seems that the issue is that the while(1){...} statement is indeed firing, but, the sem_wait(&_qSem); 更新:因此,在使用一些调试语句之后,似乎问题在于while(1){...}语句确实在触发,但是sem_wait(&_qSem); is causing it to block. 导致它被阻止。 For whatever reason it is waiting indefinitely and despite the fact that the semaphore is being posted, it continues to wait and never progress beyond that line. 无论出于何种原因,它都会无限期地等待,尽管事实上已发布了信号量,但它仍在继续等待,并且从未超出该范围。

Since you're already using boost::mutex and its scoped lock type, I suggest you use boost::condition_variable instead of a POSIX semaphore. 由于您已经在使用boost::mutex及其作用域锁定类型,因此建议您使用boost::condition_variable而不是POSIX信号量。 Otherwise you're mixing C++11-style synchronisation with POSIX synchronisation. 否则,您将C ++ 11样式的同步与POSIX同步混合在一起。

You lock the mutex when adding to the queue, but I don't see anything locking the mutex to read from the queue. 您将互斥锁添加到队列时将其锁定,但是我看不到任何锁定互斥锁以从队列读取的内容。 It also looks like you're looping back to call AsyncReadSome while the mutex is still locked. 在互斥体仍处于锁定AsyncReadSome时,您似乎还循环回调用AsyncReadSome

Pick a single form of synchronisation, and then use it correctly. 选择一种形式的同步,然后正确使用它。

The initial value of the semaphore is 0 which is valid for this case. 信号量的初始值为0,在这种情况下有效。 So it needs a sem_post for FFTHandler::AppendIn() to be unblocked. 因此它需要一个sem_post来使FFTHandler::AppendIn()解除阻塞。 But I dont see the code that invokes SerialHandler::AsyncReadSome() for the first time for the serial port to be read and the push to happen into the queue. 但是我看不到第一次调用SerialHandler::AsyncReadSome()的代码来读取串行端口并将其推送到队列中。 If you fix that part of the code, I think sem_post would happen and the FFTHandler thread would run. 如果您修复了那部分代码,我认为sem_post会发生,并且FFTHandler线程会运行。 As the first step you can have debug prints one after the sem_wait and one inside AsyncReadSome() function, and my guess is that both wont get executed. 第一步,您可以在sem_wait之后进行调试打印,并在AsyncReadSome()函数中进行调试,我的猜测是两者都不会执行。

So, essentially you would want to ensure that 'reading' gets initiated and is kept alive as part of the main thread or a different thread. 因此,从本质上讲,您将需要确保启动“读取”并将其作为主线程或其他线程的一部分保持活动状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM