mirror of https://gitee.com/bigwinds/arangodb
112 lines
3.6 KiB
Plaintext
112 lines
3.6 KiB
Plaintext
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]
|