zthread(7) ========== NAME ---- zthread - working with system threads SYNOPSIS -------- ---- // Detached threads follow POSIX pthreads API typedef void *(zthread_detached_fn) (void *args); // Attached threads get context and pipe from parent typedef void (zthread_attached_fn) (void *args, zctx_t *ctx, void *pipe); // Create a detached thread. A detached thread operates autonomously // and is used to simulate a separate process. It gets no ctx, and no // pipe. void zthread_new (zthread_detached_fn *thread_fn, void *args); // Create an attached thread. An attached thread gets a ctx and a PAIR // pipe back to its parent. It must monitor its pipe, and exit if the // pipe becomes unreadable. void * zthread_fork (zctx_t *ctx, zthread_attached_fn *thread_fn, void *args); // Self test of this class int zthread_test (Bool verbose); ---- DESCRIPTION ----------- The zthread class wraps OS thread creation. It creates detached threads that look like normal OS threads, or attached threads that share the caller's 0MQ context, and get a pipe to talk back to the parent thread. One problem is when our application needs child threads. If we simply use pthreads_create() we're faced with several issues. First, it's not portable to legacy OSes like win32. Second, how can a child thread get access to our zctx object? If we just pass it around, we'll end up sharing the pipe socket (which we use to talk to the agent) between threads, and that will then crash 0MQ. Sockets cannot be used from more than one thread at a time. So each child thread needs its own pipe to the agent. For the agent, this is fine, it can talk to a million threads. But how do we create those pipes in the child thread? We can't, not without help from the main thread. The solution is to wrap thread creation, like we wrap socket creation. To create a new thread, the app calls zctx_thread_new() and this method creates a dedicated zctx object, with a pipe, and then it passes that object to the newly minted child thread. The neat thing is we can hide non-portable aspects. Windows is really a mess when it comes to threads. Three different APIs, none of which is really right, so you have to do rubbish like manually cleaning up when a thread finishes. Anyhow, it's hidden in this class so you don't need to worry. Second neat thing about wrapping thread creation is we can make it a more enriching experience for all involved. One thing I do often is use a PAIR-PAIR pipe to talk from a thread to/from its parent. So this class will automatically create such a pair for each thread you start. EXAMPLE ------- .From zthread_test method ---- static void * s_test_detached (void *args) { // Create a socket to check it'll be automatically deleted zctx_t *ctx = zctx_new (); void *push = zsocket_new (ctx, ZMQ_PUSH); zctx_destroy (&ctx); return NULL; } static void s_test_attached (void *args, zctx_t *ctx, void *pipe) { // Create a socket to check it'll be automatically deleted zsocket_new (ctx, ZMQ_PUSH); // Wait for our parent to ping us, and pong back free (zstr_recv (pipe)); zstr_send (pipe, "pong"); } zctx_t *ctx = zctx_new (); // Create a detached thread, let it run zthread_new (s_test_detached, NULL); zclock_sleep (100); // Create an attached thread, check it's safely alive void *pipe = zthread_fork (ctx, s_test_attached, NULL); zstr_send (pipe, "ping"); char *pong = zstr_recv (pipe); assert (streq (pong, "pong")); free (pong); // Everything should be cleanly closed now zctx_destroy (&ctx); ---- SEE ALSO -------- linkczmq:czmq[7]