Hi Marc,
Thanks for your response. I believe I have all the needed locking in place.
I distilled the problem into the attached source code. TEST=1 is the
regular case, and it works as expected.
TEST=2 starts the empty loop, and then adds the watcher few seconds later.
In this case the event is fired only sixty seconds after the loop was
started (regardless of when the watcher was started).
Is there any other calls / locking I need to use in this latter case to
have the event fire right away?
Thanks,
Zoltan.
PS: The system is Ubuntu 11.10 32-bit (3.0.0.16), and the backend used by
libev is epoll.
2012. március 20. 14:11 Marc Lehmann írta, <[email protected]>:
> On Mon, Mar 19, 2012 at 09:58:24PM +0100, Zoltán Lajos Kis <
> [email protected]> wrote:
> > create an io watcher for the socket, and start the socket on the started
> > loop. (note: the request processing, and watcher preparation is done on
> > another thread.)
> > get no immediate results. However, roughly after one minute (since
> starting
> > the loop?) the events show up as they were buffered, and from that time
> > packets are
>
> since you use threads, are you sure you use proper locking? from the
> symptoms, it seems you don't - in geenral, when you access a shared
> resource (such as the event loop) you need to lock it with e.g. a mutex.
>
> > What I do now is that I set up an async watcher and a message queue to
> the
> > thread. Then instead of starting the watcher, I put the watcher ('s
> > pointer) to the queue, and notify the loop about this using the async
> > watcher.
>
> Yes - but if you don't use proper locking, you will get data corruption
> under certain circumstances. If you want to access the same loop from
> different threads, you need to lock it against concurrent access - see
> thwe thread locking example in the manual for example.
>
> > My question is whether someone could explain me what is actually going
> on,
> > and what would be a cleaner solution for the problem.
>
> 1. read the documentation, if you then sitll have questions, feel free to
> ask them.
> 2. thread programming is notoriously difficult - as a rule of thumb,
> protecting shared resources with a mutex is a must, but there are many
> other
> cases where you need to use special thread functions when working with
> threads, such as using condvars, or async watchers.
>
> failure to lock will most likely seem to work under light load, but will
> lead to memory corruption unless you are extremely lucky. it will also
> cause the symptom you describe, as if you would properly lock the loop you
> would block in the lock (because the other thread is inside ev_run).
>
> --
> The choice of a Deliantra, the free code+content MORPG
> -----==- _GNU_ http://www.deliantra.net
> ----==-- _ generation
> ---==---(_)__ __ ____ __ Marc Lehmann
> --==---/ / _ \/ // /\ \/ / [email protected]
> -=====/_/_//_/\_,_/ /_/\_\
>
#include <ev.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
/*
* TEST 1 -> normal case
* TEST 2 -> adds watcher in original thread after ev_run
*/
#define TEST 2
static struct ev_loop *loop;
static ev_io io_w;
static pthread_t thread;
static pthread_mutex_t mutex;
static void
cb(struct ev_loop *loop, ev_io *w, int revents) {
time_t now;
time(&now);
printf("callback called at %s", ctime(&now));
ev_io_stop(loop, w);
}
static void
add_watcher() {
pthread_mutex_lock(&mutex);
ev_init(&io_w, cb);
ev_io_set(&io_w, STDOUT_FILENO, EV_WRITE);
ev_io_start(loop, &io_w);
pthread_mutex_unlock(&mutex);
time_t now;
time(&now);
printf("added watcher at %s", ctime(&now));
}
static void
loop_lock(struct ev_loop *loop) {
printf("loop lock.\n");
pthread_mutex_lock(&mutex);
}
static void
loop_unlock(struct ev_loop *loop) {
printf("loop unlock.\n");
pthread_mutex_unlock(&mutex);
}
static void *
loop_thread(void *loop_) {
struct ev_loop *loop = (struct ev_loop *)loop_;
time_t now;
time(&now);
printf("loop start at %s", ctime(&now));
ev_ref(loop);
ev_run(loop, 0);
printf("should not happen.\n");
pthread_exit(NULL);
return NULL;
}
int
main(int argc, char** argv) {
pthread_mutex_init(&mutex, NULL);
loop = ev_loop_new(0);
ev_set_loop_release_cb (loop, loop_unlock, loop_lock);
if (TEST == 1) { add_watcher(); }
pthread_create(&thread, NULL, loop_thread, (void *)loop);
if (TEST == 2) { sleep(3); add_watcher(); }
pthread_exit(NULL);
return 0;
}_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev