pthread is not starting for class instance

前端 未结 1 891
既然无缘
既然无缘 2021-01-24 03:24

NOTE: C++98

Hi, I\'m a little new to c++ and I am writing a databaes program and am attempting to start a timer using the boost::asio package using pthr

1条回答
  •  鱼传尺愫
    2021-01-24 03:55

    I'm very ccnfused why anyone who uses Boost or C++11 (or both...) would ever use raw pthread threads (see e.g. C++ boost asynchronous timer to run in parallel with program for a good juxtaposition).

    The real problem is likely that you have io_service running out of work (see e.g. https://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/io_service__work.html).

    If you have no pending async operations the thread just exits.

    Another problem is accuracy issues with

    timer.expires_at(timer.expires_at() + interval);
    

    It's possible that some handlers take so much time that by the time you schedule your next alarm, the deadline has already expired. It's probably better to use

    timer.expires_from_now(interval);
    

    Note this also matches the comment better. The comment suffers from comment already because it says "1 second" but it is actually some defined constant DB_WRITE_TIME

    or separate your timer from the other handlers in some other way to guarantee accurate scheduling.

    Finally, you had UB due to the absense of any shutdown. The static instance never gets destroyed, but what's worth the non-detached thread never is joined, creating undefined behaviour at shutdown.

    This problem is actually almost identical to the one recently discussed here, where I also explains the way work guards work in more detail: asio::io_service is ending immediately with work

    Here's a c++11 rewrite with the necessary fix:

    Since I now noticed you're that person stuck in c++03 land for some weird reason, a Boost Thread version:

    C++03 DEMO/Boost Thread

    Live On Coliru

    #include 
    #include 
    #include 
    #include 
    #include 
    
    static const int DB_WRITE_TIME = 500;
    
    class Database
    {
      private:
        static boost::shared_ptr dbInstance;
    
        Database()
            : work(new io_service::work(io)),
              interval(750),
              timer(io, interval)
        {
            std::cout << "INSTANCE CREATED" << std::endl;
        }
    
        void on_timer_completed(const boost::system::error_code& ec) {
            std::cout << "[on_timer_completed] " << ec.message() << std::endl;
    
            if (!ec) {
                boost::posix_time::milliseconds interval(DB_WRITE_TIME);
    
                // Reschedule the timer
                timer.expires_from_now(interval);
                timer.async_wait(boost::bind(&Database::on_timer_completed, this, _1));
            }
        }
    
        int buffer()
        {
            // DO BUFFER STUFF
    
            timer.expires_from_now(interval);
            timer.async_wait(boost::bind(&Database::on_timer_completed, this, _1));
            // io_service.run() <-- uncommenting this results in the loop
            return 1; // rc ;
        }
    
      public:
        void do_stuff() {
            buffer(); // whatever it does
        }
    
        void teardown() {
            std::cout << "INSTANCE SHUTTING DOWN\n";
            timer.cancel(); // stop timer loop
            work.reset();   // allows io.run() to exit
            if (timerThread.joinable()) {
                timerThread.join(); // releasing the bound shared_ptr
            }
            dbInstance.reset(); // releasing the instance
        }
    
        ~Database() {
            //sqlite3_close(db);
            std::cout << "INSTANCE DESTROYED\n";
        }
    
      private:
        typedef boost::asio::io_service io_service;
        io_service io;
        boost::scoped_ptr work;
        boost::posix_time::millisec interval;
        boost::asio::deadline_timer timer;
        boost::thread timerThread;
    
        void run_io() {
            std::cout << "ENTER IO THREAD" << std::endl;
            io.run();
            std::cout << "LEAVE IO THREAD" << std::endl;
        }
    public:
        static Database &getInstance()
        {
            if (!dbInstance)
            {
                dbInstance.reset(new Database());
                dbInstance->timerThread =
                    boost::thread(boost::bind(&Database::run_io, dbInstance));
            }
            return *dbInstance;
        }
    };
    
    boost::shared_ptr Database::dbInstance;
    
    int main() {
        Database& db = Database::getInstance();
        boost::this_thread::sleep_for(boost::chrono::seconds(1));
    
        db.do_stuff();
        boost::this_thread::sleep_for(boost::chrono::seconds(3));
        // ....
    
        db.teardown();
    }
    

    Prints

    INSTANCE CREATED
    ENTER IO THREAD
    [on_timer_completed] Success
    [on_timer_completed] Success
    [on_timer_completed] Success
    [on_timer_completed] Success
    [on_timer_completed] Success
    INSTANCE SHUTTING DOWN
    [on_timer_completed] Operation canceled
    LEAVE IO THREAD
    INSTANCE DESTROYED
    

    0 讨论(0)
提交回复
热议问题