[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] std::threads



If I replace the thread code, and it works. It seems somewhere has problem with multiple threads.



On 03/18/2016 10:13 PM, Michael wrote:
Hi all,

I tried to use pthread to work with libevent. But the server can't send out data after recving a message. The detail is:

I can see that the data has been put into the evbuffer (output) using evbuffer_add_cb(bufferevent_get_output(bev_), BufferCb, tp): BufferCb info->orig_size: 0 info->n_deleted: 0 info->n_added: 19

But the underlying level didn't send out the data. and when another client coming, the server has no response (listener callback doesn't work). But when I close the server (kill the process), client can recv close signal.

I apt-get install libevent, and the version is : libevent-core-2.0-5_2.0.21-stable-1ubuntu1.14.04.1_amd64

What's the problem? Thanks!!!

  
    [server init]:

    bev_ = bufferevent_socket_new(base_, fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
    // set read callback and event callback
    bufferevent_setcb(bev_, ReadCb, NULL, EventCb, this);
    bufferevent_enable(bev_, EV_READ | EV_WRITE);

   [server read callback]:   

    bev_ = bufferevent_socket_new(base_, fd, BEV_OPT_CLOSE_ON_FREE|BEV_OPT_THREADSAFE);
    // set read callback and event callback
    bufferevent_setcb(bev_, ReadCb, NULL, EventCb, this);
    bufferevent_enable(bev_, EV_READ | EV_WRITE);

    // read is ok
    bufferevent_lock(bev_);
    struct evbuffer *input = bufferevent_get_input(bev_);
    return evbuffer_remove(input, buffer, len);
    bufferevent_unlock(bev_);

    // process read data..........
   
    // write has problem
    bufferevent_lock(bev_);
    struct evbuffer *output = bufferevent_get_output(bev_);
    int re = evbuffer_add(output, buffer, len);
    bufferevent_unlock(bev_);


 [server event_base set]:

void Listener::Run(void* arg) {

    struct sockaddr_in sin;

    /* Clear the sockaddr before using it, in case there are extra
     *          * platform-specific fields that can mess us up. */
    memset(&sin, 0, sizeof(sin));
    /* This is an INET address */
    sin.sin_family = AF_INET;
    /* Listen on 0.0.0.0 */
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    /* Listen on the given port. */
    sin.sin_port = htons(port_);

    // TODO: LEV_OPT_THREADSAFE is necessary here?
    listener_ = evconnlistener_new_bind(listen_base_, AcceptConnCb, arg,
        LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE|LEV_OPT_THREADSAFE, -1,
        (struct sockaddr*)&sin, sizeof(sin));

    if (!listener_) {
      LOG_ERROR("Couldn't create listener");
      return;
    }

    evconnlistener_set_error_cb(listener_, AcceptErrorCb);
    event_base_dispatch(listen_base_);
    return;
}



On 03/17/2016 08:50 PM, Azat Khuzhin wrote:
On Thu, Mar 17, 2016 at 05:14:22PM +0000, Tomer Heber wrote:
Hi Azat,

Correct me if I'm wrong.
Hi Tomer,

Indeed,

But he is using std c++11 "libraries" which are cross platform.
but if don't talking about cross platform then pthreads are ok on *nix,
and for win32 we have evthread_use_windows_threads()

But if you need cross platform, then you can just write something like
this (untested):
    #include <mutex>

    /** XXX: implement handle recursive locking! */
    static void *cxx_lock_alloc(unsigned /*locktype*/)
    {
        return reinterpret_cast<void *>(new std::mutex);
    }
    static void cxx_lock_free(void *lock_, unsigned /*locktype*/)
    {
        std::mutex *m = reinterpret_cast<std::mutex *>(lock_);
        delete m;
    }
    static int cxx_lock_lock(unsigned /*mode*/, void *lock_)
    {
        std::mutex *m = reinterpret_cast<std::mutex *>(lock_);
        m->lock();
    }
    static int cxx_lock_unlock(unsigned /*mode*/, void *lock_)
    {
        std::mutex *m = reinterpret_cast<std::mutex *>(lock_);
        m->unlock();
    }
    static int use_lock_unlock_profiler(void)
    {
        struct evthread_lock_callbacks cbs = {
            EVTHREAD_LOCK_API_VERSION,
            EVTHREAD_LOCKTYPE_RECURSIVE,
            cxx_lock_alloc,
            cxx_lock_free,
            cxx_lock_lock,
            cxx_lock_unlock,
        };
        evthread_set_lock_callbacks(&cbs);
        // evthread_enable_lock_debugging();

Also you can take a look at
https://github.com/libevent/libevent/blob/master/test/regress_bufferevent.c#L300

On the other hand, pthread is not cross platform.

So I think Michael shouldn't use pthreads and instead implement the callbacks (which is actually pretty straightforward).
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.