[boost][asio] boost::asio::placeholders::error
От: Аноним  
Дата: 29.11.11 16:30
Оценка:
Всем привет!
Я с asio и boost только начинаю работать и вот наткнулся на проблему.
Суть ее в том, что вываливается исключение при работе с boost::asio::placeholders.
Например, я делаю следующий вызов async_accept:

pacceptor_->async_accept(pclient->GetSocket(),
boost::bind(&CNetCopyServer::OnAccept, this, pclient,
boost::asio::placeholders::error));
Возникает исключение
Unhandled exception at 0x0053ae4e in MDBCopySrv.exe: 0xC0000005: Access violation reading location 0x00000000.

Посмотрев в дисассемблере, увидел что исключение получается на строчке:

pacceptor_->async_accept(pclient->GetSocket(),
boost::bind(&CNetCopyServer::OnAccept, this, pclient,
boost::asio::placeholders::error));

0053AE49 mov eax,dword ptr [boost::asio::placeholders::`anonymous namespace'::error (77FD34h)]
0053AE4E movzx ecx,byte ptr [eax]
0053AE51 push ecx
0053AE52 sub esp,8
0053AE55 mov ecx,esp
0053AE57 mov dword ptr [ebp-108h],esp
0053AE5D lea edx,[ebp-24h]
0053AE60 push edx
0053AE61 call boost::shared_ptr<CNetClient>::shared_ptr<CNetClient> (50A91Ch)
...

EAX = 0 и следовательно получаем исключение. Но из-за чего такое происходит?
Что я не так сделал, ведь вроде бы по туториалу пытался сделать..?
Заранее спасибо за помощь

MSVS 2008
Re: [boost][asio] boost::asio::placeholders::error
От: savitar  
Дата: 29.11.11 16:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Что я не так сделал, ведь вроде бы по туториалу пытался сделать..?


Все покажи.
Re[2]: [boost][asio] boost::asio::placeholders::error
От: fk Россия  
Дата: 30.11.11 08:12
Оценка:
Здравствуйте, savitar, Вы писали:

S>Все покажи.


///////////////////////////////////////////////////////////
// CNetCopyServer 
class CNetCopyServer : public CWorkThread
{
private:
    asio::io_service io_service_;
    tcp::acceptor * pacceptor_;

    CCopyManager * m_pCopyMgmt;

    typedef shared_ptr<CNetClient> ClientPtr;
    typedef deque<ClientPtr> ClientList;
    ClientList clients_;

    void AcceptClients();
    void OnAccept(ClientPtr new_client,
        const boost::system::error_code& error);

protected:
    virtual void OnThreadProc();
    virtual void OnInitThread();

public:
    CNetCopyServer(CCopyManager * pCopyMgmt);
    virtual ~CNetCopyServer(void);

    bool StartServer();
    bool StopServer();

};

CNetCopyServer::CNetCopyServer(CCopyManager * pCopyMgmt) : 
    CWorkThread()
{
    m_pCopyMgmt = pCopyMgmt;
    InitThread();
}
CNetCopyServer::~CNetCopyServer(void)
{
    StopServer();

    ClientList::iterator it = clients_.begin();
    for (; it!=clients_.end(); ++it)
        (*it).reset();
    clients_.clear();
}
void CNetCopyServer::OnThreadProc()
{
    io_service_.run();
}
void CNetCopyServer::OnInitThread()
{
    pacceptor_ = new tcp::acceptor(io_service_, tcp::endpoint(tcp::v4(), 5010));
    AcceptClients();
}
void CNetCopyServer::AcceptClients()
{
    ClientPtr pclient = ClientPtr(new CNetClient(io_service_, m_pCopyMgmt));

    pacceptor_->async_accept(pclient->GetSocket(),
        boost::bind(&CNetCopyServer::OnAccept, this, pclient,
        boost::asio::placeholders::error));
}
void CNetCopyServer::OnAccept( ClientPtr new_client, const boost::system::error_code& error )
{
    if (error)
        return;

    clients_.push_back(new_client);
    new_client->OnConnect();
    AcceptClients();
}
bool CNetCopyServer::StartServer()
{
    return StartThread();
}
bool CNetCopyServer::StopServer()
{
    io_service_.stop();
    return StopThread();
}

/////////////////////////////////////////////////////////
// CNetClient 
class CNetClient : public boost::enable_shared_from_this<CNetClient>
{
private:
    asio::io_service & io_service_;
    tcp::socket socket_;

    CCopyManager * m_pCopyMgmt;

    BYTE recvdata_[1024];

    void OnRead(const boost::system::error_code& error,
        std::size_t bytes_transferred);
    void OnDisconnect();

public:
    CNetClient(asio::io_service & ios, CCopyManager * pCopyMgmt);
    virtual ~CNetClient(void);

    tcp::socket & GetSocket() { return socket_; }

    bool OnConnect();
    bool Read();
};

CNetClient::CNetClient(asio::io_service & ios, CCopyManager * pCopyMgmt) :
    io_service_(ios), socket_(ios)
{
    m_pCopyMgmt = pCopyMgmt;
}
CNetClient::~CNetClient(void)
{
}
bool CNetClient::OnConnect()
{
    return true;
}
void CNetClient::OnDisconnect()
{
}
bool CNetClient::Read()
{
    asio::async_read(socket_, boost::asio::buffer(recvdata_, 1024), 
        boost::bind(&CNetClient::OnRead, this,
        boost::asio::placeholders::error,
        boost::asio::placeholders::bytes_transferred));
    return true;
}
void CNetClient::OnRead( const boost::system::error_code& error, std::size_t bytes_transferred )
{
    if (error)
        OnDisconnect();
    else
    {
        // processing 
        //RecvData(recvdata_, bytes_transferred);
        //Translate();
        Read();
    }
}

//////////////////////////////////////////////////////////////////////
// CWorkThread
// Вспомогательный класс, используется как обертка над потоком
class CWorkThread  
{
private:
    bool m_bEnabled;

    HANDLE m_hThreadHandle; // поток
    HANDLE m_hStartEvent; // старт потока
    HANDLE m_hStarted; // когда поток запустился
    HANDLE m_hStopped; // когда поток остановился (пауза)

    bool m_bStarted;

protected:
    bool m_bServiceStop;

    void InitThread(); // создает поток и события управляющие им
    void TerminateThread(); // завершить поток

    bool StartThread();
    bool StopThread();

    static DWORD __stdcall ThreadProc(LPVOID lpParameter);

    virtual void OnThreadProc() = 0;
    virtual void OnInitThread() = 0;

public:
    CWorkThread();
    virtual ~CWorkThread();

};

DWORD CWorkThread::ThreadProc( LPVOID lpParameter )
{
    CWorkThread * Me = reinterpret_cast<CWorkThread *>(lpParameter);
    
    Me->OnInitThread();

    do
    {
        if (!Me->m_bStarted || Me->m_bServiceStop)
        {
            SetEvent(Me->m_hStopped);
            WaitForSingleObject(Me->m_hStartEvent, INFINITE);
            SetEvent(Me->m_hStarted);
        }
        else
        {
            Me->OnThreadProc();
        }
    }
    while (Me->m_bEnabled);
    
    return 0;    
}
Re[3]: [boost][asio] boost::asio::placeholders::error
От: savitar  
Дата: 30.11.11 10:51
Оценка:
Здравствуйте, fk, Вы писали:

Ничего криминального в указанном месте нет. Видимо где-то память хериться.
Re[4]: [boost][asio] boost::asio::placeholders::error
От: fk Россия  
Дата: 30.11.11 13:46
Оценка: 14 (3)
Здравствуйте, savitar, Вы писали:

S>Ничего криминального в указанном месте нет. Видимо где-то память хериться.


Как оказалось дело было в следующем.
В самом начале запуска программы происходит инициализация глобальных переменных,
в том числе и boost::asio::placeholders::error
  boost::arg<1>& error
    = boost::asio::placeholders::detail::placeholder<1>::get();

После этого вывоза она инициализируется, все хорошо.. &error показывает валидный адрес
Эта инициализация вызывается три раза. Причем между ними &error показывает 0.

Моя программа — это сервис windows, и я делаю ее с помощью ATL, где
есть класс CAtlServiceModuleT, который помогает в создании сервиса и управлении им.
Создание внутренних объектов происходит прямо в конструкторе моего унаследованного класса.
CMDBCopySrvModule() : CAtlServiceModuleT()
{
    m_pCopyManager = new CCopyManager();
    m_pNetServer = new CNetCopyServer(m_pCopyManager);
    m_pNetServer->StartServer();
}

Объект этого класса тоже является глобальной переменной и ее создание происходит вместе с placeholders::error.
Причем она вклинивается между теми тремя инициализациями placeholders::error.
И получается что уже в конструкторе моего класса &error = 0.
(На момент входа в этот конструктор &error еще валидный. Но дальше происходит нечто странное.
Как только я захожу в конструктор CCopyManager, &error становиться равен 0.)

Проблема решилась переносом создания внутренних объектов в метод RunMessageLoop.
Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

Но я по-прежнему не понимаю где &error успевает обнуляться между этими вызовами и почему их три?
CRT каким-то хитрым способом строит список инициализации или что?
Re[5]: [boost][asio] boost::asio::placeholders::error
От: о_О
Дата: 30.11.11 15:07
Оценка: +1
Здравствуйте, fk, Вы писали:

fk>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

fk>CRT каким-то хитрым способом строит список инициализации или что?

у vc++ можно ведь самому установить порядок инициализации глобальных переменных, вот только не помню директиву.
Re[6]: [boost][asio] boost::asio::placeholders::error
От: Mazay Россия  
Дата: 01.12.11 14:37
Оценка:
Здравствуйте, о_О, Вы писали:

о_О>Здравствуйте, fk, Вы писали:


fk>>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

о_О>в asio какое-то порно с глобальными переменными.

Глобальные переменные — это как езда по разделительной полосе. Всё ОК, пока не ещё одного такого же не встретишь.
Главное гармония ...
Re[6]: [boost][asio] boost::asio::placeholders::error
От: jazzer Россия Skype: enerjazzer
Дата: 02.12.11 04:58
Оценка:
Здравствуйте, о_О, Вы писали:

fk>>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

о_О>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

багрепорт уже отправили им?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: [boost][asio] boost::asio::placeholders::error
От: fk Россия  
Дата: 02.12.11 06:33
Оценка:
Здравствуйте, jazzer, Вы писали:

J>багрепорт уже отправили им?


Пока еще нет. Сейчас надо проект быстро доделать.
Попробую потом как-нибудь сделать, с английским правда проблема..
Re[7]: [boost][asio] boost::asio::placeholders::error
От: Mazay Россия  
Дата: 02.12.11 06:51
Оценка:
Здравствуйте, jazzer, Вы писали:

fk>>>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

о_О>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>багрепорт уже отправили им?


Какой смысл? Всё равно нормального решения нет.
Главное гармония ...
Re[8]: [boost][asio] boost::asio::placeholders::error
От: jazzer Россия Skype: enerjazzer
Дата: 02.12.11 07:13
Оценка:
Здравствуйте, Mazay, Вы писали:

M>Здравствуйте, jazzer, Вы писали:


fk>>>>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

о_О>>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>>багрепорт уже отправили им?


M>Какой смысл? Всё равно нормального решения нет.


Ну О_о, видимо, решение знает, раз так резко высказывается...
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[7]: [boost][asio] boost::asio::placeholders::error
От: о_О
Дата: 02.12.11 07:20
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, о_О, Вы писали:


fk>>>Получается что нельзя пользоваться asio в конструкторе глобальных объектов, так как некоторые его объекты еще не до конца созданы.

о_О>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>багрепорт уже отправили им?


зачем? что я ему скажу? "эй, линуксоид, кто ж WSAStartup на глобальную переменную вешает?"
Re[8]: [boost][asio] boost::asio::placeholders::error
От: jazzer Россия Skype: enerjazzer
Дата: 02.12.11 08:13
Оценка:
Здравствуйте, о_О, Вы писали:

о_О>>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>>багрепорт уже отправили им?
о_О>зачем? что я ему скажу? "эй, линуксоид, кто ж WSAStartup на глобальную переменную вешает?"

если уберешь "линуксоид" и приведешь вместо этого цитату из MSDN, а еще лучше, пример падающей программы — то да.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: [boost][asio] boost::asio::placeholders::error
От: о_О
Дата: 02.12.11 08:44
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, о_О, Вы писали:


о_О>>>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>>>багрепорт уже отправили им?
о_О>>зачем? что я ему скажу? "эй, линуксоид, кто ж WSAStartup на глобальную переменную вешает?"

J>если уберешь "линуксоид" и приведешь вместо этого цитату из MSDN, а еще лучше, пример падающей программы — то да.


нуу... эту проблему можно решить путем добавления флага компиляции ASIO_MANUAL_INITIALIZATION, но...

*тут было очень много разоблачающего текста*
Re[10]: [boost][asio] boost::asio::placeholders::error
От: jazzer Россия Skype: enerjazzer
Дата: 02.12.11 09:04
Оценка:
Здравствуйте, о_О, Вы писали:

о_О>Здравствуйте, jazzer, Вы писали:


J>>Здравствуйте, о_О, Вы писали:


о_О>>>>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>>>>багрепорт уже отправили им?
о_О>>>зачем? что я ему скажу? "эй, линуксоид, кто ж WSAStartup на глобальную переменную вешает?"

J>>если уберешь "линуксоид" и приведешь вместо этого цитату из MSDN, а еще лучше, пример падающей программы — то да.


о_О>нуу... эту проблему можно решить путем добавления флага компиляции ASIO_MANUAL_INITIALIZATION, но...


о_О>*тут было очень много разоблачающего текста*


Давай ты это все изложишь на английском и трекере буста, а сюда ссылку?
Я тебе даже помогу:
https://svn.boost.org/trac/boost/newticket
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[11]: [boost][asio] boost::asio::placeholders::error
От: abrarov Россия http://asio-samples.blogspot.com/
Дата: 02.12.11 09:52
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Давай ты это все изложишь на английском и трекере буста, а сюда ссылку?

J>Я тебе даже помогу:
J>https://svn.boost.org/trac/boost/newticket

Давно "мечтал", чтобы инициализация и деинициализация Asio были вынесены явно (например, в некоторый scoped guard класс). Вообще, мне кажется, любая библиотека, требующая инициализации/деинициализация должна позволять делать это явно (если не требовать). Ваше мнение?
Вот еще кое-что по теме, но из другого "королевства" — TBB initialization, termination, and resource management details, juicy and gory:

This means that auto-initialization, with all its convenience, may restrict your ability to control concurrency of parallel computations. The only consolation is that fortunately this is rarely an issue in practice.

Programs must be written for people to read, and only incidentally for machines to execute
Re[11]: [boost][asio] boost::asio::placeholders::error
От: о_О
Дата: 02.12.11 10:17
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, о_О, Вы писали:


о_О>>Здравствуйте, jazzer, Вы писали:


J>>>Здравствуйте, о_О, Вы писали:


о_О>>>>>>в asio какое-то порно с глобальными переменными. в курсе, что WSAStartup вызывается так же и чем это грозит?

J>>>>>багрепорт уже отправили им?
о_О>>>>зачем? что я ему скажу? "эй, линуксоид, кто ж WSAStartup на глобальную переменную вешает?"

J>>>если уберешь "линуксоид" и приведешь вместо этого цитату из MSDN, а еще лучше, пример падающей программы — то да.


о_О>>нуу... эту проблему можно решить путем добавления флага компиляции ASIO_MANUAL_INITIALIZATION, но...


о_О>>*тут было очень много разоблачающего текста*


J>Давай ты это все изложишь на английском и трекере буста, а сюда ссылку?

J>Я тебе даже помогу:
J>https://svn.boost.org/trac/boost/newticket

с ним не о чем говорить:
https://svn.boost.org/trac/boost/ticket/3605
Re[12]: [boost][asio] boost::asio::placeholders::error
От: о_О
Дата: 02.12.11 10:25
Оценка:
Здравствуйте, abrarov, Вы писали:

A>Вообще, мне кажется, любая библиотека, требующая инициализации/деинициализация должна позволять делать это явно (если не требовать). Ваше мнение?


она обязана не производить инициализацию/деинициализацию автоматически, если используются системные библиотеки. это требование Windows, а требования API ОС надо соблюдать
но конкретно крис колхоф — линуксоид и такое порно у него уже 8 лет
Re[12]: [boost][asio] boost::asio::placeholders::error
От: jazzer Россия Skype: enerjazzer
Дата: 02.12.11 10:33
Оценка:
Здравствуйте, о_О, Вы писали:

о_О>с ним не о чем говорить:

о_О>https://svn.boost.org/trac/boost/ticket/3605

Ну так переоткрой тикет и спроси, не пришло ли время, делов то.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[12]: [boost][asio] boost::asio::placeholders::error
От: abrarov Россия http://asio-samples.blogspot.com/
Дата: 02.12.11 10:36
Оценка:
Здравствуйте, о_О, Вы писали:

о_О>с ним не о чем говорить:

о_О>https://svn.boost.org/trac/boost/ticket/3605

Ну хотя бы с WSAStartup/WSACleanup там есть решение. Да. Что касается boost::asio::placeholders, то они мне "сразу не понравились". Перейду на boost::arg<> и на _N.
Programs must be written for people to read, and only incidentally for machines to execute
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.