C ++信号量混乱?

时间:2016-07-07 23:16:14

标签: c++ multithreading boost-asio semaphore

所以,我正在编写一种示波器式程序,它读取计算机上的串行端口并对此数据执行fft以将其转换为频谱。我遇到了一个问题,我的程序布局分为SerialHandler类(利用boost::Asio),FFTHandler类和main函数。 SerialHandler类使用boost::Asio`` async_read_some函数从端口读取并引发一个名为HandleOnPortReceive的事件,然后读取数据本身。

问题是我找不到一种方法将事件处理程序中的数据从另一个线程上的io_service对象引发到FFTHandler类,该类已在另一个线程。我被建议使用信号量来解决我的问题,但我几乎没有关于semaphore.h使用的知识,所以我的实现现在已经相当破碎,并没有做任何应该做的事情。

如果能让它更清晰一些,可以使用以下代码:

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();
                    }
                }

         }
    }

}

FFTHandler::AppendIn(..)中的调试行确实正在触发,因此正在创建线程,但是它似乎超出了范围,并且破坏了线程,因为我似乎已经设置了一段时间来不正确地响应到信号量。

TLDR :这是一个很长的解释,简单地说,“我不理解信号量,但需要以某种方式实现它们。我尝试过,失败了,所以现在我来这里希望收到从比我更了解的人那里获得有关此代码的帮助。

更新:因此,在使用了一些调试语句后,似乎问题是while(1){...}语句确实正在触发,但sem_wait(&_qSem);导致它阻止。无论出于什么原因,它无限期地等待,尽管信号量正在被发布,但它仍在等待,并且永远不会超越该线。

2 个答案:

答案 0 :(得分:2)

由于您已经在使用boost::mutex及其范围锁定类型,因此我建议您使用boost::condition_variable而不是POSIX信号量。否则,您将C ++ 11风格的同步与POSIX同步混合在一起。

在添加到队列时锁定互斥锁,但是我没有看到任何锁定互斥锁以从队列中读取的内容。当互斥锁仍处于锁定状态时,您似乎还在回拨AsyncReadSome

选择一种形式的同步,然后正确使用它。

答案 1 :(得分:1)

信号量的初始值为0,对于这种情况有效。所以它需要一个sem_post来解除p的阻塞。但我没有看到第一次调用FFTHandler::AppendIn()的代码,以便读取串口并推送到队列中。如果你修复了那部分代码,我认为会发生sem_post并且FFTHandler线程会运行。作为第一步,您可以在sem_wait之后进行调试打印,并在AsyncReadSome()函数内打印一个,我的猜测是两者都不会被执行。

所以,基本上你会想要确保阅读&#39;启动并作为主线程或不同线程的一部分保持活动状态。