C++ 从共享缓冲区写入文件丢失数据和程序崩溃

C++ 从共享缓冲区写入文件丢失数据和程序崩溃,c++,multithreading,file,crash,C++,Multithreading,File,Crash,我正在使用线程和共享缓冲区制作一个程序。这两个线程在后台无限期运行,一个线程将用数据填充共享缓冲区,另一个线程将共享缓冲区的内容写入文件 用户可以启动或停止数据填充,这会导致线程进入等待状态,直到用户再次启动线程。缓冲区中的每个循环填充50个浮点数 代码如下: #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 使用名称空间std; std::互斥m; std::条件变量cv; std::矢量数据; bool keep_running=true,start_running=fals

我正在使用线程和共享缓冲区制作一个程序。这两个线程在后台无限期运行,一个线程将用数据填充共享缓冲区,另一个线程将共享缓冲区的内容写入文件

用户可以启动或停止数据填充,这会导致线程进入等待状态,直到用户再次启动线程。缓冲区中的每个循环填充50个浮点数

代码如下:


#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
std::互斥m;
std::条件变量cv;
std::矢量数据;
bool keep_running=true,start_running=false;
无效写入线程()
{
流文件;
bool-opn=false;
而(1)
{
while(保持运行)
{
//只打开文件一次
如果(!opn)
{
myfile.open(“IQ_Datas.txt”);
opn=真;
}
//等待main()发送数据
std::唯一锁lk(m);
wait(lk,[{return!datas.empty();});
自动d=标准::移动(数据);
lk.unlock();
用于(自动输入:d)
{
用于(自动和电气:输入)
myfile要避免:

Moved-from object 'datas' of type 'std::vector' is moved:
        auto d = std::move(datas);
                 ^~~~~~~~~~~~~~~~
替换此项:

        // Wait until main() sends data
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, [] {return !datas.empty();});
        auto d = std::move(datas);
        lk.unlock();
如果您想在关机后继续提取数据,可以将
extract\u all()
更改为:

   std::vector<std::vector<T>> extract_all() {
        std::vector<std::vector<T>> return_value;

        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_data.empty() && m_shutdown == false) m_cv.wait(lock);

        m_current_elements = 0;
        return_value.swap(m_data);
        m_cv.notify_one();

        return return_value;
    }
std::向量提取_all(){
std::向量返回值;
std::唯一锁定(m_mtx);
while(m_data.empty()&&m_shutdown==false)m_cv.wait(lock);
m_当前_元素=0;
返回值交换(m_数据);
m_cv.通知_one();
返回_值;
}
完整的示例如下所示:

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <fstream>
#include <iostream>
#include <iterator>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class atomic2dvector {
public:
    atomic2dvector(size_t max_elements) : m_max_elements(max_elements) {}
    atomic2dvector(const atomic2dvector&) = delete;
    atomic2dvector(atomic2dvector&&) = delete;
    atomic2dvector& operator=(const atomic2dvector&) = delete;
    atomic2dvector& operator=(atomic2dvector&&) = delete;

    ~atomic2dvector() { shutdown(); }

    bool insert_one(std::vector<T>&& other) {
        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_current_elements + m_data.size() > m_max_elements &&
              m_shutdown == false)
            m_cv.wait(lock);
        if(m_shutdown) return false;

        m_current_elements += other.size();
        m_data.emplace_back(std::forward<std::vector<T>>(other));

        m_cv.notify_one();
        return true;
    }
    std::vector<std::vector<T>> extract_all() {
        std::vector<std::vector<T>> return_value;

        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_data.empty() && m_shutdown == false) m_cv.wait(lock);

        m_current_elements = 0;
        return_value.swap(m_data);
        m_cv.notify_one();

        return return_value;
    }

    bool is_active() const { return m_shutdown == false; }

    void shutdown() {
        m_shutdown = true;
        m_cv.notify_all();
    }

private:
    size_t m_max_elements;
    size_t m_current_elements = 0;
    std::atomic<bool> m_shutdown = false;
    std::condition_variable m_cv{};
    std::mutex m_mtx{};
    std::vector<std::vector<T>> m_data{};
};

std::mutex m;
std::condition_variable cv;
atomic2dvector<float> datas(256 * 1024 * 1024 / sizeof(float)); // 0.25 GiB limit
std::atomic_bool start_running = false;

void writing_thread() {
    std::ofstream myfile("IQ_Datas.txt");
    if(myfile) {
        std::cout << "writing_thread waiting\n";

        std::vector<std::vector<float>> d;
        while((d = datas.extract_all()).empty() == false) {
            std::cout << "got " << d.size() << "\n";

            for(auto& entry : d) {
                for(auto& e : entry) myfile << e << "\n";
            }
            std::cout << "wrote " << d.size() << "\n\n";
        }
    }
    std::cout << "writing_thread shutting down\n";
}

void sending_thread() {
    std::vector<float> m_buffer;
    std::uintmax_t cpt = 0;
    // Fill the buffer with 50 floats
    for(float i = 0; i < 50; i++) m_buffer.push_back(i);

    while(true) {
        {
            std::unique_lock<std::mutex> lk(m);
            cv.wait(lk, [] {
                return start_running == true || datas.is_active() == false;
            });
        }
        if(datas.is_active() == false) break;
        std::cout << "sending...\n";
        while(start_running == true) {
            // Each loop d is containing 50 floats
            std::vector<float> d = m_buffer;
            if(datas.insert_one(std::move(d)) == false) break;
            cpt++;
        }
        cout << "Total data: " << cpt * 50 << endl;
        cpt = 0;
    }
    std::cout << "sending_thread shutting down\n";
}

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 quit() {
    datas.shutdown();
    cv.notify_all();
}

int main() {
    int go = 0;
    thread t1(sending_thread);
    thread t2(writing_thread);

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Enter 1 to make the sending thread send and 0 to make it stop "
                 "sending. Enter a non-integer to shutdown.\n";

    while(std::cin >> go) {
        if(go == 1) {
            start();
        } else if(go == 0) {
            stop();
        }
    }
    std::cout << "--- shutting down ---\n";
    quit();

    std::cout << "joining threads\n";
    t1.join();
    std::cout << "t1 joined\n";
    t2.join();
    std::cout << "t2 joined\n";
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
模板
类原子向量{
公众:
原子2dvector(size_t max_elements):m_max_elements(max_elements){}
原子2dvector(常量原子2dvector&)=删除;
atomic2dvector(atomic2dvector&&)=删除;
atomic2dvector&运算符=(常量atomic2dvector&)=删除;
atomic2dvector&运算符=(atomic2dvector&&)=删除;
~atomic2dvector(){shutdown();}
bool insert_one(标准::向量和其他){
std::唯一锁定(m_mtx);
而(m_当前元素+m_数据.size()>m_最大元素)&&
m_shutdown==false)
m_cv.等待(锁定);
如果(m_shutdown)返回false;
m_当前_元素+=其他.size();
m_数据。向后放置(标准::向前(其他));
m_cv.通知_one();
返回true;
}
std::向量提取_all(){
std::向量返回值;
std::唯一锁定(m_mtx);
while(m_data.empty()&&m_shutdown==false)m_cv.wait(lock);
m_当前_元素=0;
返回值交换(m_数据);
m_cv.通知_one();
返回_值;
}
bool is_active()const{return m_shutdown==false;}
无效关机(){
m_shutdown=真;
m_cv.通知所有人();
}
私人:
最大元素的大小;
当前元素的大小=0;
std::原子m_关机=错误;
std::条件变量m_cv{};
std::mutexm_mtx{};
std::向量m_数据{};
};
std::互斥m;
std::条件变量cv;
atomic2dvector数据(256*1024*1024/sizeof(float));//0.25 GiB限制
std::原子启动运行=false;
无效写入线程(){
std::流myfile(“IQ_data.txt”);
如果(我的文件){
标准::不能避免:

Moved-from object 'datas' of type 'std::vector' is moved:
        auto d = std::move(datas);
                 ^~~~~~~~~~~~~~~~
替换此项:

        // Wait until main() sends data
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, [] {return !datas.empty();});
        auto d = std::move(datas);
        lk.unlock();
如果您想在关机后继续提取数据,可以将
extract\u all()
更改为:

   std::vector<std::vector<T>> extract_all() {
        std::vector<std::vector<T>> return_value;

        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_data.empty() && m_shutdown == false) m_cv.wait(lock);

        m_current_elements = 0;
        return_value.swap(m_data);
        m_cv.notify_one();

        return return_value;
    }
std::向量提取_all(){
std::向量返回值;
std::唯一锁定(m_mtx);
while(m_data.empty()&&m_shutdown==false)m_cv.wait(lock);
m_当前_元素=0;
返回值交换(m_数据);
m_cv.通知_one();
返回_值;
}
完整的示例如下所示:

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <fstream>
#include <iostream>
#include <iterator>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
class atomic2dvector {
public:
    atomic2dvector(size_t max_elements) : m_max_elements(max_elements) {}
    atomic2dvector(const atomic2dvector&) = delete;
    atomic2dvector(atomic2dvector&&) = delete;
    atomic2dvector& operator=(const atomic2dvector&) = delete;
    atomic2dvector& operator=(atomic2dvector&&) = delete;

    ~atomic2dvector() { shutdown(); }

    bool insert_one(std::vector<T>&& other) {
        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_current_elements + m_data.size() > m_max_elements &&
              m_shutdown == false)
            m_cv.wait(lock);
        if(m_shutdown) return false;

        m_current_elements += other.size();
        m_data.emplace_back(std::forward<std::vector<T>>(other));

        m_cv.notify_one();
        return true;
    }
    std::vector<std::vector<T>> extract_all() {
        std::vector<std::vector<T>> return_value;

        std::unique_lock<std::mutex> lock(m_mtx);
        while(m_data.empty() && m_shutdown == false) m_cv.wait(lock);

        m_current_elements = 0;
        return_value.swap(m_data);
        m_cv.notify_one();

        return return_value;
    }

    bool is_active() const { return m_shutdown == false; }

    void shutdown() {
        m_shutdown = true;
        m_cv.notify_all();
    }

private:
    size_t m_max_elements;
    size_t m_current_elements = 0;
    std::atomic<bool> m_shutdown = false;
    std::condition_variable m_cv{};
    std::mutex m_mtx{};
    std::vector<std::vector<T>> m_data{};
};

std::mutex m;
std::condition_variable cv;
atomic2dvector<float> datas(256 * 1024 * 1024 / sizeof(float)); // 0.25 GiB limit
std::atomic_bool start_running = false;

void writing_thread() {
    std::ofstream myfile("IQ_Datas.txt");
    if(myfile) {
        std::cout << "writing_thread waiting\n";

        std::vector<std::vector<float>> d;
        while((d = datas.extract_all()).empty() == false) {
            std::cout << "got " << d.size() << "\n";

            for(auto& entry : d) {
                for(auto& e : entry) myfile << e << "\n";
            }
            std::cout << "wrote " << d.size() << "\n\n";
        }
    }
    std::cout << "writing_thread shutting down\n";
}

void sending_thread() {
    std::vector<float> m_buffer;
    std::uintmax_t cpt = 0;
    // Fill the buffer with 50 floats
    for(float i = 0; i < 50; i++) m_buffer.push_back(i);

    while(true) {
        {
            std::unique_lock<std::mutex> lk(m);
            cv.wait(lk, [] {
                return start_running == true || datas.is_active() == false;
            });
        }
        if(datas.is_active() == false) break;
        std::cout << "sending...\n";
        while(start_running == true) {
            // Each loop d is containing 50 floats
            std::vector<float> d = m_buffer;
            if(datas.insert_one(std::move(d)) == false) break;
            cpt++;
        }
        cout << "Total data: " << cpt * 50 << endl;
        cpt = 0;
    }
    std::cout << "sending_thread shutting down\n";
}

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 quit() {
    datas.shutdown();
    cv.notify_all();
}

int main() {
    int go = 0;
    thread t1(sending_thread);
    thread t2(writing_thread);

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Enter 1 to make the sending thread send and 0 to make it stop "
                 "sending. Enter a non-integer to shutdown.\n";

    while(std::cin >> go) {
        if(go == 1) {
            start();
        } else if(go == 0) {
            stop();
        }
    }
    std::cout << "--- shutting down ---\n";
    quit();

    std::cout << "joining threads\n";
    t1.join();
    std::cout << "t1 joined\n";
    t2.join();
    std::cout << "t2 joined\n";
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
模板
类原子向量{
公众:
原子2dvector(size_t max_elements):m_max_elements(max_elements){}
原子2dvector(常量原子2dvector&)=删除;
atomic2dvector(atomic2dvector&&)=删除;
atomic2dvector&运算符=(常量atomic2dvector&)=删除;
atomic2dvector&运算符=(atomic2dvector&&)=删除;
~atomic2dvector(){shutdown();}
bool insert_one(标准::向量和其他){
std::唯一锁定(m_mtx);
而(m_当前元素+m_数据.size()>m_最大元素)&&
m_shutdown==false)
m_cv.等待(锁定);
如果(m_shutdown)返回false;
m_当前_元素+=其他.size();
m_数据。向后放置(标准::向前(其他));
m_cv.通知_one();
返回true;
}
std::向量提取_all(){
std::向量返回值;
std::唯一锁定(m_mtx);
while(m_data.empty()&&m_shutdown==false)m_cv.wait(lock);
m_当前_元素=0;
返回值交换(m_数据);
m_cv.通知_one();
返回_值;
}
bool is_active()const{return m_shutdown==false;}
无效关机(){
m_shutdown=真;
m_cv.通知所有人();
}
私人:
最大元素的大小;
当前元素的大小=0;
std::原子m_关机=错误;
std::条件变量m_cv{};
std::mutexm_mtx{};
std::向量m_数据{};
};
std::互斥m;
std::条件变量cv;
atomic2dvector数据(256*1024*1024/sizeof(float));//0.25 GiB限制
std::原子启动运行=false;
无效写入线程(){
std::流myfile(“IQ_data.txt”);
如果(我的文件){
std::难道看起来是y吗