繁体   English   中英

在线程之间填充和保存共享缓冲区

[英]Filling and saving shared buffer between threads

我正在使用一个检索I / Q数据的API。 调用函数bbGetIQ(m_handle, &pkt); 填充缓冲区。 这是一个线程循环,而用户没有输入“停止”。 Pkt是一个结构,使用的缓冲区是pkt.iqData = &m_buffer[0]; 这是一个浮动的向量。 向量的大小为5000,每次循环缓冲区时都会填充5000个值。

我想将缓冲区中的数据保存到文件中,我在调用bbgetIQ之后就bbgetIQ但这样做是一项耗时的任务,数据检索速度不够快,导致API丢弃数据,因此它可以继续填充缓冲区。

这是我的代码的样子:


void Acquisition::recordIQ(){

    int cpt = 0;
    ofstream myfile;


    while(1){

        while (keep_running)
        {   

            cpt++;

            if(cpt < 2)
                myfile.open ("/media/ssd/IQ_Data.txt");


            bbGetIQ(m_handle, &pkt); //Retrieve I/Q data


            //Writing content of buffer into the file.
            for(int i=0; i<m_buffer.size(); i++)
                myfile << m_buffer[i] << endl;


        }
        cpt = 0;
        myfile.close();
    }
}

然后我尝试在离开循环时只写入文件:



void Acquisition::recordIQ(){

    int cpt = 0;
    ofstream myfile;
    int next=0;
    vector<float> data;


    while(1){

        while ( keep_running)
        {   
            if(keep_running == false){

                myfile.open ("/media/ssd/IQ_Data.txt");

                for(int i=0; i<data.size(); i++)
                    myfile << data[i] << endl;

                myfile.close();
                break;
            }

            cpt++;

            data.resize(next + m_buffer.size());

            bbGetIQ(m_handle, &pkt); //retrieve data

            std::copy(m_buffer.begin(), m_buffer.end(), data.begin() + next); //copy content of the buffer into final vector

            next += m_buffer.size(); //next index

        }

        cpt = 0;

    }
}

我不再从API中获取数据丢失,但问题在于我受data向量大小的限制。 例如,我不能让它整夜检索数据。

我的想法是制作2个帖子。 一个将检索数据,另一个将数据写入文件。 2个线程将共享一个循环缓冲区,第一个线程将填充缓冲区,第二个线程将读取缓冲区并将内容写入文件。 由于它是一个共享缓冲区,我想我应该使用互斥锁。

我是多线程和互斥的新手,所以这是个好主意吗? 我真的不知道从哪里开始以及消费者线程如何在生产者填充它时读取缓冲区。 读取时锁定缓冲区是否会导致数据丢失? (因为它无法将其写入循环缓冲区)。

编辑 :因为我希望我的记录线程在后台运行,所以我可以在录制时做其他的东西,我分离它,用户可以通过将条件keep_running设置为true来启动记录。


thread t1(&Acquisition::recordIQ, &acq);
t1.detach();

你需要使用这样的东西( https://en.cppreference.com/w/cpp/thread/condition_variable ):

全局:

std::mutex m;
std::condition_variable cv;
std::vector<std::vector<float>> datas;
bool keep_running = true, start_running = false;

写线程:

void writing_thread()
{
    myfile.open ("/media/ssd/IQ_Data.txt");

    while(1) {
        // Wait until main() sends data
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return keep_running && !datas.empty();});
        if (!keep_running) break;

        auto d = std::move(datas); 
        lk.unlock();

        for(auto &entry : d) {
            for(auto &e : entry)
                myfile << e << endl;             
        }
    }
}

发送线程:

void sending_thread() {
    while(1) {
        {
            std::unique_lock<std::mutex> lk(m);
            cv.wait(lk, []{return keep_running && start_running;});
            if (!keep_running) break;
        }

        bbGetIQ(m_handle, &pkt); //retrieve data

        std::vector<float> d = m_buffer;

        {
            std::lock_guard<std::mutex> lk(m);
            if (!keep_running) break;
            datas.push_back(std::move(d));
        }
        cv.notify_one();
    }
}
void start() {
    {
        std::unique_lock<std::mutex> lk(m);
        start_running = true;
    }
    cv.notify_all();
}
void stop() {
    {
        std::unique_lock<std::mutex> lk(m);
        start_running = false;
    }
    cv.notify_all();
}
void terminate() {
    {
        std::unique_lock<std::mutex> lk(m);
        keep_running = false;
    }
    cv.notify_all();

    thread1.join();
    thread2.join();
}

总之:发送线程接收来自任何说到数据,锁定互斥mt和移动数据datas存储。 然后它使用cv条件变量来通知等待的线程,有事情要做。 写入线程等待条件变量发出信号,然后锁定互斥锁mt数据从datas全局变量移动到本地,然后释放互斥锁并继续将接收到的数据写入文件。 关键是尽可能锁定互斥锁。

编辑:要终止整个事情,你需要将keep_running设置为false。 然后调用cv.notify_all() 然后加入涉及的线程。 订单很重要。 您需要连接线程,因为编写线程可能仍在处理数据。

EDIT2:加入延迟开始。 现在创建两个线程,在一个运行sending_thread ,在其他writing_thread 调用start()启用处理,使用stop()停止处理。

暂无
暂无

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

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