Boost logo

Boost Users :

Subject: [Boost-users] Boost.Asio server application close get "This application has requested the Runtime to terminate it in an unusual way."
From: l.jay Yuan (pass86_at_[hidden])
Date: 2010-03-06 03:53:19


Boost.Asio server application close get "This application has
requested the Runtime to terminate it in an unusual way."

My code is too mush!

std.hpp:
/*
** author: ylj
** create: 2009/08/27
*/

#ifndef STD_HPP
#define STD_HPP

#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <strstream>
#include <utility>
#include <vector>

#include <cassert>
#include <cctype>
#include <cerrno>
#include <cfloat>
#include <climits>
#include <clocale>
#include <cmath>
#include <csetjmp>
#include <csignal>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <cwchar>
#include <cwctype>

#endif // STD_HPP

tcontainer.hpp:
/*
** author: ylj
** create: 2010/02/10
*/

#ifndef TCONTAINER_HPP
#define TCONTAINER_HPP

#include <deque>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <vector>

#if 0

#include <boost/pool/pool_alloc.hpp>

template<typename T>
class tvector : public std::vector<T, boost::pool_allocator<T> >
{
};

template<typename T>
class tdeque: public std::deque<T, boost::pool_allocator<T> >
{
};

template<typename T>
class tlist: public std::list<T, boost::fast_pool_allocator<T> >
{
};

template<typename T>
class tstack: public std::stack<T, tdeque<T> >
{
};

template<typename T>
class tqueue: public std::queue<T, tdeque<T> >
{
};

template<typename T>
class tpriority_queue: public std::priority_queue<T, tdeque<T> > /*
NOTE: use tvector will crash if compiled by gcc, why? */
{
};

template<typename T>
class tset: public std::set<T, std::less<T>, boost::pool_allocator<T> >
{
};

template<typename T>
class tmultiset: public std::multiset<T, std::less<T>,
boost::pool_allocator<T> >
{
};

template<typename K, typename V>
class tmap: public std::map<K, V, std::less<K>,
boost::pool_allocator<std::pair<K, V> > >
{
};

template<typename K, typename V>
class tmultimap: public std::multimap<K, V, std::less<K>,
boost::pool_allocator<std::pair<K, V> > >
{
};

#else

template<typename T>
class tvector : public std::vector<T>
{
};

template<typename T>
class tdeque: public std::deque<T>
{
};

template<typename T>
class tlist: public std::list<T>
{
};

template<typename T>
class tstack: public std::stack<T, tdeque<T> >
{
};

template<typename T>
class tqueue: public std::queue<T, tdeque<T> >
{
};

template<typename T>
class tpriority_queue: public std::priority_queue<T>
{
};

template<typename T>
class tset: public std::set<T>
{
};

template<typename T>
class tmultiset: public std::multiset<T>
{
};

template<typename K, typename V>
class tmap: public std::map<K, V>
{
};

template<typename K, typename V>
class tmultimap: public std::multimap<K, V>
{
};

#endif

#endif // TCONTAINER_HPP

tstring.hpp:
/*
** author: ylj
** create: 2010/02/20
*/

#ifndef TSTRING_HPP
#define TSTRING_HPP

#include <string>
#include <sstream>
#include <boost/pool/pool_alloc.hpp>

typedef std::basic_string<char, std::char_traits<char>,
boost::pool_allocator<char> > tstring;
typedef std::basic_string<wchar_t, std::char_traits<wchar_t>,
boost::pool_allocator<wchar_t> > twstring;

typedef std::basic_stringstream<char, std::char_traits<char>,
boost::pool_allocator<char> > tstringstream;
typedef std::basic_stringstream<wchar_t, std::char_traits<wchar_t>,
boost::pool_allocator<wchar_t> > twstringstream;

typedef std::basic_istringstream<char, std::char_traits<char>,
boost::pool_allocator<char> > tistringstream;
typedef std::basic_istringstream<wchar_t, std::char_traits<wchar_t>,
boost::pool_allocator<wchar_t> > twistringstream;

typedef std::basic_ostringstream<char, std::char_traits<char>,
boost::pool_allocator<char> > tostringstream;
typedef std::basic_ostringstream<wchar_t, std::char_traits<wchar_t>,
boost::pool_allocator<wchar_t> > twostringstream;

typedef std::basic_stringbuf<char, std::char_traits<char>,
boost::pool_allocator<char> > tstringbuf;
typedef std::basic_stringbuf<wchar_t, std::char_traits<wchar_t>,
boost::pool_allocator<wchar_t> > twstringbuf;

#endif // TSTRING_HPP

tcp_packet.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef TCP_PACKET_H_
#define TCP_PACKET_H_

#define TCP_PACKET_HEARTBEAT_COMMAND -1

#include "std.hpp"

class tcp_packet
{
public:
    typedef struct header {
        unsigned short length;
        int command;
    } header;

    enum { header_length = sizeof(header), max_body_length = 1024 * 4 };

public:
    tcp_packet() : body_length_(0), command_(0) {}

    inline const char * data() const { return data_; }
    inline char * data() { return data_; }
    inline size_t length() const { return header_length + body_length_; }

    inline int command() const { return command_; }
    inline void command(int cmd) { command_ = cmd; }

    inline const char * body() const { return data_ + header_length; }
    inline char * body() { return data_ + header_length; }
    inline size_t body_length() const{ return body_length_; }
    inline void body_length(size_t length) {
        body_length_ = length;
        if (body_length_ > max_body_length)
            body_length_ = max_body_length;
    }

    inline bool decode_header() {
        using namespace std;
        header hd;
        memcpy(&hd, data_, header_length);
        body_length_ = hd.length;
        command_ = hd.command;
        if (body_length_ > max_body_length) {
            body_length_ = 0;
            command_ = 0;
            return false;
        }
        return true;
    }
    inline void encode_header() {
        using namespace std;
        header hd;
        hd.length = body_length_;
        hd.command = command_;
        memcpy(data_, &hd, header_length);
    }

private:
    char data_[header_length + max_body_length];
    size_t body_length_;
    int command_;
};

#endif // TCP_PACKET_H_

net_command.h:
/*
** author: ylj
** create: 2010/03/05
*/

#ifndef NET_COMMAND_H_
#define NET_COMMAND_H_

#define NET_CMD_GAME_CLIENT_TO_GAME_SERVER_START 1000
#define NET_CMD_GAME_SERVER_TO_GAME_CLIENT_START 2000
#define NET_CMD_LOBBY_CLIENT_TO_LOBBY_SERVER_START 3000
#define NET_CMD_LOBBY_SERVER_TO_LOBBY_CLIENT_START 4000

#endif // NET_COMMAND_H_

net_command_game_client_to_game_server.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_
#define NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_

#include "net_command.h"

enum NET_CMD_GC_TO_GS {
    NET_CMD_GC_TO_GS_START = NET_CMD_GAME_CLIENT_TO_GAME_SERVER_START,

    NET_CMD_GC_TO_GS_TEST
};

typedef struct CMD_GC_TO_GS_TEST {
    unsigned short x;
    unsigned short y;
} CMD_GC_TO_GS_TEST;

#endif // NET_COMMAND_GAME_CLIENT_TO_GAME_SERVER_H_

net_command_game_server_to_game_client.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_
#define NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_

#include "net_command.h"

enum NET_CMD_GS_TO_GC {
    NET_CMD_GS_TO_GC_START = NET_CMD_GAME_SERVER_TO_GAME_CLIENT_START,

    NET_CMD_GS_TO_GC_TEST,
};

typedef struct CMD_GS_TO_GC_TEST {
    unsigned int id;
    unsigned short x;
    unsigned short y;
} CMD_GS_TO_GC_TEST;

#endif // NET_COMMAND_GAME_SERVER_TO_GAME_CLIENT_H_

tcp_server.h:
/*
** author: ylj
** create: 2010/02/26
*/

#ifndef TCP_SERVER_H_
#define TCP_SERVER_H_

#include "tcp_session.h"
#include "tcontainer.hpp"
#include <boost/asio.hpp>

class tcp_server_club;

class tcp_server
{
public:
    tcp_server(boost::asio::io_service &io_service,
               const boost::asio::ip::tcp::endpoint &endpoint,
               tcp_server_club &club,
               int max_session_count);
    virtual ~tcp_server();

    tcp_session * take_session();
    void release_session(int session_id);

    void accept();
    int active_count() const;
    void close();

private:
    void handle_accept(tcp_session *session, const
boost::system::error_code &error);
    void do_accept();
    void do_close();

private:
    typedef tdeque<tcp_session *> tcp_session_container;
    typedef tmap<int, tcp_session *> tcp_session_map;

    tcp_session_container idle_sessions_;
    tcp_session_map active_sessions_;
    boost::asio::io_service &io_service_;
    boost::asio::ip::tcp::acceptor acceptor_;
    tcp_server_club &club_;
    int max_session_count_;
};

#endif // TCP_SERVER_H_

tcp_server.cpp:
/*
** author: ylj
** create: 2010/02/26
*/

#include "tcp_server.h"
#include "tcp_session.h"
#include "tcp_server_club.h"
#include <boost/bind.hpp>

tcp_server::tcp_server(boost::asio::io_service &io_service,
                       const boost::asio::ip::tcp::endpoint &endpoint,
                       tcp_server_club &club,
                       int max_session_count)
                       : io_service_(io_service),
acceptor_(io_service, endpoint), club_(club)
{
    max_session_count_ = max_session_count;
    for (int i = 0; i < max_session_count; ++i) {
        tcp_session *session(new tcp_session(io_service_, club_, this, i));
        idle_sessions_.push_back(session);
    }
}

tcp_server::~tcp_server()
{
    tcp_session_container::iterator it = idle_sessions_.begin();
    for ( ; it != idle_sessions_.end(); ++it)
        delete *it;
    tcp_session_map::iterator ufo = active_sessions_.begin();
    for ( ; ufo != active_sessions_.end(); ++ufo)
        delete ufo->second;
    assert(max_session_count_ == (int)idle_sessions_.size() +
(int)active_sessions_.size());
}

tcp_session * tcp_server::take_session()
{
    std::cout << "tcp_server::take_session" << std::endl;
    if (idle_sessions_.empty())
        return NULL;
    tcp_session *ret = idle_sessions_.front();
    idle_sessions_.pop_front();
    active_sessions_.insert(std::make_pair(ret->id(), ret));
    return ret;
}

void tcp_server::release_session(int session_id)
{
    std::cout << "tcp_server::release_session" << std::endl;
    tcp_session_map::iterator it = active_sessions_.find(session_id);
    if (it == active_sessions_.end())
        return;
    tcp_session *session = it->second;
    club_.leave(session);
    session->socket().close();
    idle_sessions_.push_front(session);
    active_sessions_.erase(it);

    /* can accept again */
    if (idle_sessions_.size() == 1 && acceptor_.is_open()) {
        do_accept();
    }
}

void tcp_server::accept()
{
    std::cout << "tcp_server::accept" << std::endl;
    io_service_.post(boost::bind(&tcp_server::do_accept, this));
}

int tcp_server::active_count() const
{
    return static_cast<int>(active_sessions_.size());
}

void tcp_server::close()
{
    std::cout << "tcp_server::close" << std::endl;
    io_service_.post(boost::bind(&tcp_server::do_close, this));
}

void tcp_server::handle_accept(tcp_session *session, const
boost::system::error_code &error)
{
    std::cout << "tcp_server::handle_accept" << std::endl;
    if (!error) {
        club_.join(session);
        session->start();
        do_accept();
    }
    else {
        std::cout << "tcp_server::handle_accept error" << std::endl;
        session->socket().close();
    }
}

void tcp_server::do_accept()
{
    std::cout << "tcp_server::do_accept" << std::endl;
    tcp_session *new_session = take_session();
    if (new_session)
        acceptor_.async_accept(new_session->socket(),
                               boost::bind(&tcp_server::handle_accept,
this, new_session, boost::asio::placeholders::error));
}

void tcp_server::do_close()
{
    std::cout << "tcp_server::do_close" << std::endl;
    acceptor_.close();
    tcp_session_map all_active = active_sessions_;
    tcp_session_map::iterator it = all_active.begin();
    for ( ; it != all_active.end(); ++it) {
        tcp_session *session = it->second;
        session->socket().close();
    }
}

tcp_session.h:
/*
** author: ylj
** create: 2010/02/26
*/

#ifndef TCP_SESSION_H_
#define TCP_SESSION_H_

#include "tcp_packet.h"
#include "tcp_server_member.h"
#include "tcontainer.hpp"
#include <boost/asio.hpp>

class tcp_server;
class tcp_server_club;

class tcp_session : public tcp_server_member
{
public:
    tcp_session(boost::asio::io_service &io_service, tcp_server_club
&club, tcp_server *parent, int id);
    ~tcp_session();

    boost::asio::ip::tcp::socket & socket();

    void start();

    void send(const tcp_packet &pkt);

    virtual int id() const;
    virtual tstring address() const;
    virtual unsigned short port() const;
    virtual void send(int command, void *data, int size);
    virtual void close();

private:
    void handle_read_header(const boost::system::error_code &error);
    void handle_read_body(const boost::system::error_code &error);
    void handle_write(const boost::system::error_code &error);

private:
    typedef tdeque<tcp_packet> tcp_packet_queue;

    boost::asio::ip::tcp::socket socket_;
    tcp_server_club &club_;
    tcp_packet read_packet_;
    tcp_packet_queue write_packets_;
    tcp_server *parent_;
    int id_;
};

#endif // TCP_SESSION_H_

tcp_session.cpp:
/*
** author: ylj
** create: 2010/03/01
*/

#include "tcp_session.h"
#include "tcp_server.h"
#include "tcp_server_club.h"
#include <boost/bind.hpp>

tcp_session::tcp_session(boost::asio::io_service &io_service,
                         tcp_server_club &club,
                         tcp_server *parent,
                         int id)
                         : socket_(io_service),
                           club_(club),
                           parent_(parent),
                           id_(id)
{
}

tcp_session::~tcp_session()
{
}

boost::asio::ip::tcp::socket & tcp_session::socket()
{
    return socket_;
}

void tcp_session::start()
{
    boost::asio::async_read(socket_,
                            boost::asio::buffer(read_packet_.data(),
tcp_packet::header_length),

boost::bind(&tcp_session::handle_read_header, this,
boost::asio::placeholders::error));
}

void tcp_session::send(const tcp_packet &pkt)
{
    bool write_in_progress = !write_packets_.empty();
    write_packets_.push_back(pkt);
    if (!write_in_progress) {
        boost::asio::async_write(socket_,

boost::asio::buffer(write_packets_.front().data(),
write_packets_.front().length()),

boost::bind(&tcp_session::handle_write, this,
boost::asio::placeholders::error));
    }
}

int tcp_session::id() const
{
    return id_;
}

tstring tcp_session::address() const
{
    return socket_.remote_endpoint().address().to_string().c_str();
}

unsigned short tcp_session::port() const
{
    return socket_.remote_endpoint().port();
}

void tcp_session::send(int command, void *data, int size)
{
    assert(tcp_packet::max_body_length >= size);
    tcp_packet pkt;
    pkt.command(command);
    pkt.body_length(size);
    memcpy(pkt.body(), data, pkt.body_length());
    pkt.encode_header();
    this->send(pkt);
}

void tcp_session::close()
{
    socket_.close();
}

void tcp_session::handle_read_header(const boost::system::error_code &error)
{
    if (!error && read_packet_.decode_header()) {
        boost::asio::async_read(socket_,

boost::asio::buffer(read_packet_.body(), read_packet_.body_length()),

boost::bind(&tcp_session::handle_read_body, this,
boost::asio::placeholders::error));
    }
    else {
        parent_->release_session(id_);
    }
}

void tcp_session::handle_read_body(const boost::system::error_code &error)
{
    if (!error) {
        if (read_packet_.command() != TCP_PACKET_HEARTBEAT_COMMAND)
            club_.receive(this, read_packet_.command(),
read_packet_.body(), read_packet_.body_length());
        boost::asio::async_read(socket_,

boost::asio::buffer(read_packet_.data(), tcp_packet::header_length),

boost::bind(&tcp_session::handle_read_header, this,
boost::asio::placeholders::error));
    }
    else {
        parent_->release_session(id_);
    }
}

void tcp_session::handle_write(const boost::system::error_code &error)
{
    if (!error) {
        write_packets_.pop_front();
        if (!write_packets_.empty()) {
            boost::asio::async_write(socket_,

boost::asio::buffer(write_packets_.front().data(),
write_packets_.front().length()),

boost::bind(&tcp_session::handle_write, this,
boost::asio::placeholders::error));
        }
    }
    else {
        parent_->release_session(id_);
    }
}

tcp_server_member.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef TCP_SERVER_MEMBER_H_
#define TCP_SERVER_MEMBER_H_

#include "tstring.hpp"

class tcp_server_member
{
public:
    virtual ~tcp_server_member() {}
    virtual int id() const = 0;
    virtual tstring address() const = 0;
    virtual unsigned short port() const = 0;
    virtual void send(int command, void *data, int size) = 0;
    virtual void close() = 0;
};

#endif // TCP_SERVER_MEMBER_H_

tcp_server_club.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef TCP_SERVER_CLUB_H_
#define TCP_SERVER_CLUB_H_

#include "tcontainer.hpp"
#include <boost/function.hpp>

class tcp_server_member;

class tcp_server_club
{
public:
    virtual ~tcp_server_club();

    void receive(tcp_server_member *member, int command, void *data, int size);

    template <typename ReceiveHandler>
    void bind_receive_handler(int command, ReceiveHandler handler);

    virtual void join(tcp_server_member *member);
    virtual void leave(tcp_server_member *member);

private:
    typedef boost::function<void (tcp_server_member *, void *, int)>
receive_handler;
    typedef tmap<int, receive_handler> receive_handler_map;

    receive_handler_map receive_handlers_;
};

template <typename ReceiveHandler>
void tcp_server_club::bind_receive_handler(int command, ReceiveHandler
handler) {
    receive_handlers_.insert(std::make_pair(command, handler));
}

#endif // TCP_SERVER_CLUB_H_

tcp_server_club.cpp:
/*
** author: ylj
** create: 2010/03/01
*/

#include "tcp_server_club.h"
#include "tcp_server_member.h"
#include "std.hpp"

tcp_server_club::~tcp_server_club()
{
}

void tcp_server_club::receive(tcp_server_member *member, int command,
void *data, int size)
{
    receive_handler_map::iterator it = receive_handlers_.find(command);
    if (it != receive_handlers_.end()) {
        receive_handler handler = it->second;
        handler(member, data, size);
    }
    else {
        std::cout << "unhandle session(" << member->id() << ")'s
command: " << command << std::endl;
    }
}

void tcp_server_club::join(tcp_server_member *member)
{
}

void tcp_server_club::leave(tcp_server_member *member)
{
}

game_server_club.h:
/*
** author: ylj
** create: 2010/03/01
*/

#ifndef GAME_SERVER_CLUB_H_
#define GAME_SERVER_CLUB_H_

#include "tcp_server_club.h"

class game_server_club : public tcp_server_club
{
public:
    game_server_club();

    virtual void join(tcp_server_member *member);
    virtual void leave(tcp_server_member *member);

    void ON_NET_CMD_GC_TO_GS_TEST(tcp_server_member *member, void
*data, int size);
};

#endif // GAME_SERVER_CLUB_H_

game_server_club.cpp:
/*
** author: ylj
** create: 2010/03/01
*/

#include "game_server_club.h"
#include "tcp_server_member.h"
#include "net_command_game_server_to_game_client.h"
#include "net_command_game_client_to_game_server.h"
#include "std.hpp"
#include <boost/bind.hpp>

game_server_club::game_server_club()
{
    bind_receive_handler(NET_CMD_GC_TO_GS_TEST,
boost::bind(&game_server_club::ON_NET_CMD_GC_TO_GS_TEST, this, _1, _2,
_3));
}

void game_server_club::join(tcp_server_member *member)
{
    std::cout << "id:" << member->id() << " join(" <<
member->address() << ":" << member->port() << ")" << std::endl;
}

void game_server_club::leave(tcp_server_member *member)
{
    std::cout << "id:" << member->id() << " leave(" <<
member->address() << ":" << member->port() << ")" << std::endl;
}

void game_server_club::ON_NET_CMD_GC_TO_GS_TEST(tcp_server_member
*member, void *data, int size)
{
    CMD_GC_TO_GS_TEST *rdata = (CMD_GC_TO_GS_TEST *)data;
    CMD_GS_TO_GC_TEST sdata;
    sdata.x = rdata->x;
    sdata.y = rdata->y;
    sdata.id= member->id();
    std::cout << "id:" << sdata.id << " ON_NET_CMD_GC_TO_GS_TEST " <<
rdata->x << " " << rdata->y << std::endl;
    member->send(NET_CMD_GS_TO_GC_TEST, &sdata, sizeof(sdata));
    //member->close();
}

main.cpp:
/*
** author: ylj
** create: 2010/03/01
*/

#include "std.hpp"
#include "tcp_server.h"
#include "game_server_club.h"
#include "tstring.hpp"
#include <boost/thread.hpp>

using namespace std;

#ifdef _MSC_VER
#include <dbghelp.h>
#include <stdio.h>
#include <crtdbg.h>
#include <tchar.h>
#include <windows.h>

#pragma comment ( lib, "dbghelp.lib" )

///////////////////////////////////////////////////////////////////////////////
// Minidump creation function
//

void CreateMiniDump( EXCEPTION_POINTERS* pep )
{
        // Open the file

        HANDLE hFile = CreateFile( _T("MaxiDump.dmp"), GENERIC_READ | GENERIC_WRITE,
                0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

        if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
        {
                // Create the minidump

                MINIDUMP_EXCEPTION_INFORMATION mdei;

                mdei.ThreadId = GetCurrentThreadId();
                mdei.ExceptionPointers = pep;
                mdei.ClientPointers = FALSE;

                MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithFullMemory |
                                                          MiniDumpWithFullMemoryInfo |
                                                          MiniDumpWithHandleData |
                                                          MiniDumpWithThreadInfo |
                                                          MiniDumpWithUnloadedModules );

                BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
                        hFile, mdt, (pep != 0) ? &mdei : 0, 0, 0 );

                if( !rv )
                        _tprintf( _T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError() );
                else
                        _tprintf( _T("Minidump created.\n") );

                // Close the file

                CloseHandle( hFile );

        }
        else
        {
                _tprintf( _T("CreateFile failed. Error: %u \n"), GetLastError() );
        }

}
#endif // _MSC_VER

void do_work(int argc, const char *argv[])
{
    if (argc != 2) {
      std::cerr << "Usage: " << argv[0] << " <port>\n";
      return;
    }
    boost::asio::io_service io_service;
    boost::asio::ip::tcp::endpoint
endpoint(boost::asio::ip::tcp::v4(), atoi(argv[1]));
    game_server_club game_club;
    tcp_server game_server(io_service, endpoint, game_club, 2);
    game_server.accept();
    boost::thread io_thread(boost::bind(&boost::asio::io_service::run,
&io_service));
    tstring line;
    cout << "? for help" << endl;
    while(getline(cin, line)) {
        if (line == "exit") {
            game_server.close();
            break;
        }
        else if (line == "?") {
            cout << "exit ->close server" << endl;
            cout << "? ->help" << endl;
        }
    }
    io_thread.join();
}

int main(int argc, const char *argv[])
{
#ifdef _MSC_VER
         __try
        {
#endif // _MSC_VER
                do_work(argc, argv);
#ifdef _MSC_VER
        }
        __except( CreateMiniDump( GetExceptionInformation() ),
EXCEPTION_EXECUTE_HANDLER )
        {
        }
#endif // _MSC_VER
    return 0;
}

If anyone conneted server and not close, I type "exit" to close server
then got "This application has requested the Runtime to terminate it
in an unusual way."
I have check and check and check.
I cannot find out why.
Anyone can help me?
Thank you first.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net