pthread没有为类实例启动 [英] pthread is not starting for class instance

查看:77
本文介绍了pthread没有为类实例启动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:C ++ 98

您好,我对c ++有点陌生,我正在编写一个databaes程序,并尝试使用pthread的boost :: asio包启动计时器.计时器的目的是在将sql查询放入缓冲区后启动,如果一段时间未接收到任何内容,缓冲区将运行execute函数.我设法将其编译,但看起来pthread实例似乎没有启动.

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 pthread. The aim of the timer is to start after sql queries have been placed inside a buffer, of which will run an execute function if nothing has been received for a period of time. I have managed to get it to compile, but it doesn't look like the pthread instance is starting.

我已经在我的getInstance方法中调用了pthread,并且相应地设置了boost :: asio警报.我将在下面显示的是,通过直接调用io_run()来启动计时器,该计时器会在警报内陷入循环.

I have called the pthread inside my getInstance method, and the boost::asio alarm has been set up accordingly. What I will show below is that by calling io_run() directly starts the timer falls into a loop within the alarm.

数据库.h

void *run_io(void *arg);

class Database
{
private:
    static Database *dbInstance; //= NULL;

public:
    boost::asio::io_service io_service;
    boost::posix_time::millisec interval;
    boost::asio::deadline_timer timer;
    pthread_t timerThread;

public:
    static Database &getInstance()
    {
        if (!dbInstance)
        {
            dbInstance = new Database();
            // pthread_create(&dbInstance->timerThread,NULL,run_io,&dbInstance->io_service);
            std::cout << " INSTANCE CREATED " << std::endl;
            pthread_create(&dbInstance->timerThread, NULL, run_io, (void *)&dbInstance->io_service);
            // pthread_join(&dbInstance->timerThread, NULL);
        }
        return *dbInstance;
    }
};

database.cpp

Database *Database::dbInstance = NULL;

Database::Database()
    : interval(2000), timer(io_service, interval) {}

Database::~Database()
{
    sqlite3_close(db);
}

void Database::setAlarm(const boost::system::error_code& /* e */)
{
    std::cout << "[TEST] WE ARE IN SET ALARM " << std::endl;
    DB_WRITE_TIME = 500;

    boost::posix_time::milliseconds interval(DB_WRITE_TIME);

    // Reschedule the timer for 1 second in the future:
    timer.expires_at(timer.expires_at() + interval);
    // Posts the timer event
    timer.async_wait(boost::bind(&Database::setAlarm, this, _1));
}

int Database::buffer()
{
    // DO BUFFER STUFF

    timer.async_wait(boost::bind(&Database::setAlarm, this, _1));
   // io_service.run() <-- uncommenting this results in the loop
    return rc ;
}

void *run_io(void *arg)
{
    boost::asio::io_service *io_service = (boost::asio::io_service *)arg;

    io_service->run();
}

所以我觉得pthread甚至还没有启动.我尝试在其中放一个打印语句,看看它是否出来了,但终端中什么也没出现.

So I don't feel like the pthread is even starting. I tried putting a print statement in there to see if it came out, and nothing appeared in my terminal.

我已经按照Sehe的建议进行了更改,但是看起来仍然无法调用警报处理程序(setAlarm()).我必须对其稍作修改以使其与整个程序兼容,但实际上就是这样(我给间隔时间指定了5000的值,以使其有足够的时间进行测试):

I have made changes as per Sehe's advice, however it still does not look like I am able to call the alarm handler (setAlarm()). I had to slightly modify it to be compatible with the whole program, but essentially it is this (I gave the interval time a value of 5000 to give it enough time for the tests):

数据库.h

class Database
{
private:
    static boost::shared_ptr<Database> dbInstance;

private:
    typedef boost::asio::io_service io_service;
    io_service io;
    boost::scoped_ptr<io_service::work> 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)
        {
            std::cout << " INSTANCE CREATED " << std::endl;
            dbInstance.reset(new Database());
            dbInstance->timerThread = boost::thread(boost::bind(&Database::run_io,dbInstance));
        }
        return *dbInstance;
    }

    Database(); // <-- default constructor (doesn't take any args)
    ~Database();

database.cpp

boost::shared_ptr<Database> Database::dbInstance;
static const int DB_WRITE_TIME = 5000;

Database::Database()
    : work(new io_service::work(io)), interval(5000), timer(io, interval)
{
    // std::cout << " CONSTRUCTED " << std::endl;
}

Database::~Database()
{
    // std::cout << " DESTROYED " << std::endl;
    // sqlite3_close(db);
}

void Database::setAlarm(const boost::system::error_code& ec)
{
    std::cout << "[TEST] WE ARE IN SET ALARM - ec message = " << ec.message() << std::endl;

    executeSqlInBuffer(); // once timer expire, call the execute function

    if(!ec)
    {
        boost::posix_time::milliseconds interval(DB_WRITE_TIME);
        timer.expires_from_now(interval);
        timer.async_wait(boost::bind(&Database::setAlarm, this, _1));
    }
}

void Database::teardown()
{
    // std::cout << " INSTANCE SHUTTING DOWN " << std::endl;
    timer.cancel();             // stop timer loop
    work.reset();               // allows io.run() to exit
    if(timerThread.joinable())
    {
        std::cout << " JOINED " << std::endl;
        timerThread.join();     // releasing bound of shared_ptr
    }
    else std::cout << " NOT JOINED " << std::endl;
    dbInstance.reset();         // releasing instance
}

int Database::buffer()
{
    // do buffering
    if(buffer.size() == max_size)
    {    
        executeSqlInBuffer();
    }
    std::cout << timer.expires_from_now(interval) << std::endl;
    // std::cout << " ~ BEFORE TIMER ~ " << std::endl;
    timer.async_wait(boost::bind(&Database::setAlarm, this, _1));

    return 1;
}

main.cpp

int main()
{
    pthread_t thread1;        // a few pthreads in main that handle other areas of the program.
    pthread_create(&thread1,NULL,thread1Arg,NULL);

    pthread_t dbThread;        // my pthread for the database
    pthread_create(&dbThread,NULL,dbThreadArg,NULL);

    Database& database = Database::getInstance();
    database.teardown();

    pthread_join(thread1,NULL);
    pthread_join(dbThread,NULL);

    return 0;
}

您还可以在此处看到它进入和离开IO线程,并创建一个实例,以及timer.expires_from_now(interval)的调试输出:

You can also see here that it enters and leaves the IO thread, and creates an instance, plus the debug output for timer.expires_from_now(interval):

 INSTANCE CREATED 

 JOINED 
ENTER IO THREAD
LEAVE IO THREAD
...
...
0 ---> first cycle
1 ---> second cycle
...
1 ---> nth cycle 

推荐答案

我非常困惑为什么使用Boost或C ++ 11(或同时使用两者)的任何人都将使用原始的pthread线程(请参见例如 C ++ Boost异步计时器可以并行运行与程序配合使用)

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).

真正的问题很可能是您的io_service用尽了工作(请参见例如

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

请注意,这也可以更好地匹配注释.该注释已经受注释的困扰,因为它说"1秒",但实际上它是一些已定义的常量DB_WRITE_TIME

或以其他方式将您的计时器与其他处理程序分开,以确保准确的安排.

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

最后,由于没有任何关机,您拥有 UB .静态实例永远不会被破坏,但值得的是,从未连接的非分离线程永远不会被连接,从而在关机时会产生未定义的行为.

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.

这个问题实际上与这里最近讨论的问题几乎相同,在此我也详细解释了work警卫的工作方式:

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

下面是对c ++ 11的重写,其中包含必要的修复程序:

由于我现在注意到您由于某种奇怪的原因而陷入了c ++ 03领域,因此使用了Boost Thread版本:

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

在Coliru上直播

Live On Coliru

#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>

static const int DB_WRITE_TIME = 500;

class Database
{
  private:
    static boost::shared_ptr<Database> 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<io_service::work> 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> 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();
}

打印

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

这篇关于pthread没有为类实例启动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆