使用CZMQ-4.1.0新zsock API更新的异步Majordomo模式示例无效
使用brew安装zmq和czmq后,我尝试编译并播放,但由于需要czmq v3,因此无法运行。据我所知,我试图使用zactor将其更新到v4,因为使用CZMQ-4.1.0新zsock API更新的异步Majordomo模式示例无效,c,multithreading,zeromq,C,Multithreading,Zeromq,使用brew安装zmq和czmq后,我尝试编译并播放,但由于需要czmq v3,因此无法运行。据我所知,我试图使用zactor将其更新到v4,因为 zthread被弃用,取而代之的是zactor 所以现在,下面的代码在我看来是更新的async majordomo模式,但是它没有像预期的那样工作,当我通过终端运行它时,它没有创建任何线程 // Round-trip demonstrator // While this example runs in a single process, that
zthread
被弃用,取而代之的是zactor
所以现在,下面的代码在我看来是更新的async majordomo模式,但是它没有像预期的那样工作,当我通过终端运行它时,它没有创建任何线程
// Round-trip demonstrator
// While this example runs in a single process, that is just to make
// it easier to start and stop the example. The client task signals to
// main when it's ready.
#include "czmq.h"
#include <stdlib.h>
void dbg_write_in_file(char * txt, int nb_request) {
FILE * pFile;
pFile = fopen ("myfile.txt","a");
if (pFile!=NULL)
{
fputs (txt, pFile);
char str_nb_request[12];
sprintf(str_nb_request, "%d", nb_request);
fputs (str_nb_request, pFile);
fputs ("\n", pFile);
fclose (pFile);
}
}
static void
client_task (zsock_t *pipe, void *args)
{
zsock_t *client = zsock_new (ZMQ_DEALER);
zsock_connect (client, "tcp://localhost:5555");
printf ("Setting up test...\n");
zclock_sleep (100);
printf("child 1: parent: %i\n\n", getppid());
printf("child 1: my pid: %i\n\n", getpid());
int requests;
int64_t start;
printf ("Synchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 10000; requests++) {
zstr_send (client, "hello");
// stuck here /!\
char *reply = zstr_recv (client);
zstr_free (&reply);
// check if it does something
dbg_write_in_file("sync round-trip requests : ", requests);
// end check
}
printf (" %d calls/second\n",
(1000 * 10000) / (int) (zclock_time () - start));
printf ("Asynchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 100000; requests++) {
zstr_send (client, "hello");
// check if it does something
dbg_write_in_file("async round-trip send requests : ", requests);
// end check
}
for (requests = 0; requests < 100000; requests++) {
char *reply = zstr_recv (client);
zstr_free (&reply);
// check if it does something
dbg_write_in_file("async round-trip rec requests : ", requests);
// end check
}
printf (" %d calls/second\n",
(1000 * 100000) / (int) (zclock_time () - start));
zstr_send (pipe, "done");
}
// Here is the worker task. All it does is receive a message, and
// bounce it back the way it came:
static void
worker_task (zsock_t *pipe, void *args)
{
printf("child 2: parent: %i\n\n", getppid());
printf("child 2: my pid: %i\n\n", getpid());
zsock_t *worker = zsock_new (ZMQ_DEALER);
zsock_connect (worker, "tcp://localhost:5556");
while (true) {
zmsg_t *msg = zmsg_recv (worker);
zmsg_send (&msg, worker);
}
zsock_destroy (&worker);
}
// Here is the broker task. It uses the zmq_proxy function to switch
// messages between frontend and backend:
static void
broker_task (zsock_t *pipe, void *args)
{
printf("child 3: parent: %i\n\n", getppid());
printf("child 3: my pid: %i\n\n", getpid());
// Prepare our sockets
zsock_t *frontend = zsock_new (ZMQ_DEALER);
zsock_bind (frontend, "tcp://localhost:5555");
zsock_t *backend = zsock_new (ZMQ_DEALER);
zsock_bind (backend, "tcp://localhost:5556");
zmq_proxy (frontend, backend, NULL);
zsock_destroy (&frontend);
zsock_destroy (&backend);
}
// Finally, here's the main task, which starts the client, worker, and
// broker, and then runs until the client signals it to stop:
int main (void)
{
// Create threads
zactor_t *client = zactor_new (client_task, NULL);
assert (client);
zactor_t *worker = zactor_new (worker_task, NULL);
assert (worker);
zactor_t *broker = zactor_new (broker_task, NULL);
assert (broker);
// Wait for signal on client pipe
char *signal = zstr_recv (client);
zstr_free (&signal);
zactor_destroy (&client);
zactor_destroy (&worker);
zactor_destroy (&broker);
return 0;
}
更新
感谢@user3666197的详细回答。在第一部分中,编译器不编译assert调用,所以我只显示值,并进行可视化比较,它们是相同的
int czmqMAJOR,
czmqMINOR,
czmqPATCH;
zsys_version ( &czmqMAJOR, &czmqMINOR, &czmqPATCH );
printf( "INF: detected CZMQ ( %d, %d, %d ) -version\n",
czmqMAJOR,
czmqMINOR,
czmqPATCH
);
printf( "INF: CZMQ_VERSION_MAJOR %d, CZMQ_VERSION_MINOR %d, CZMQ_VERSION_PATCH %d\n",
CZMQ_VERSION_MAJOR,
CZMQ_VERSION_MINOR,
CZMQ_VERSION_PATCH
);
输出:
INF: detected CZMQ ( 4, 1, 0 ) -version
INF: CZMQ_VERSION_MAJOR 4, CZMQ_VERSION_MINOR 1, CZMQ_VERSION_PATCH 0
zsys_info调用会编译,但不会在终端上显示任何内容,即使带有fflush(stdout)
以防万一,所以我刚才使用了printf
:
INF: This system's Context() limit is 65535 ZeroMQ socketsINF: current state of the global Context()-instance has:
( 1 )-IO-threads ready
( 1 )-ZMQ_BLOCKY state
然后,我用zsys\u set\u io\u线程(2)
和/或zmq\u ctx\u集(aGlobalCONTEXT,zmq\u BLOCKY,false)更改了全局上下文线程值代码>,仍被阻止。看起来zactor不像zthread那样与系统线程一起工作。。。或者没有给出类似的行为。鉴于我在zeromq(也是zero)方面的经验,我可能会尝试一些无法实现的事情
已解决更新,但未执行更新
我的主要错误是没有正确启动zactor实例
actor函数在初始化时必须调用zsock_信号(pipe),并且必须侦听pipe并在$TERM命令上退出
并且在调用zactor\u destroy(&proxy)之前没有阻止zactor的代理执行代码>
我在下面给出了最后一段代码,但您仍然需要在最后使用Ctrl+C退出,因为我没有弄清楚如何正确管理$TERM
信号。此外,zactor似乎仍然没有使用系统硬盘。它可能是这样设计的,但我不知道它是如何在木头后面工作的
// Round-trip demonstrator
// While this example runs in a single process, that is just to make
// it easier to start and stop the example. The client task signals to
// main when it's ready.
#include <czmq.h>
static void
client_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Client"));
zsock_signal (pipe, 0);
zsock_t *client = zsock_new (ZMQ_DEALER);
zsock_connect (client, "tcp://127.0.0.1:5555");
printf ("Setting up test...\n");
zclock_sleep (100);
int requests;
int64_t start;
printf ("Synchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 10000; requests++) {
zstr_send (client, "hello");
zmsg_t *msgh = zmsg_recv (client);
zmsg_destroy (&msgh);
}
printf (" %d calls/second\n",
(1000 * 10000) / (int) (zclock_time () - start));
printf ("Asynchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 100000; requests++) {
zstr_send (client, "hello");
}
for (requests = 0; requests < 100000; requests++) {
char *reply = zstr_recv (client);
zstr_free (&reply);
}
printf (" %d calls/second\n",
(1000 * 100000) / (int) (zclock_time () - start));
zstr_send (pipe, "done");
printf("send 'done' to pipe\n");
}
// Here is the worker task. All it does is receive a message, and
// bounce it back the way it came:
static void
worker_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Worker"));
zsock_signal (pipe, 0);
zsock_t *worker = zsock_new (ZMQ_DEALER);
zsock_connect (worker, "tcp://127.0.0.1:5556");
bool terminated = false;
while (!terminated) {
zmsg_t *msg = zmsg_recv (worker);
zmsg_send (&msg, worker);
// zstr_send (worker, "hello back"); // Give better perf I don't know why
}
zsock_destroy (&worker);
}
// Here is the broker task. It uses the zmq_proxy function to switch
// messages between frontend and backend:
static void
broker_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Task"));
zsock_signal (pipe, 0);
// Prepare our proxy and its sockets
zactor_t *proxy = zactor_new (zproxy, NULL);
zstr_sendx (proxy, "FRONTEND", "DEALER", "tcp://127.0.0.1:5555", NULL);
zsock_wait (proxy);
zstr_sendx (proxy, "BACKEND", "DEALER", "tcp://127.0.0.1:5556", NULL);
zsock_wait (proxy);
bool terminated = false;
while (!terminated) {
zmsg_t *msg = zmsg_recv (pipe);
if (!msg)
break; // Interrupted
char *command = zmsg_popstr (msg);
if (streq (command, "$TERM")) {
terminated = true;
printf("broker received $TERM\n");
}
freen (command);
zmsg_destroy (&msg);
}
zactor_destroy (&proxy);
}
// Finally, here's the main task, which starts the client, worker, and
// broker, and then runs until the client signals it to stop:
int main (void)
{
// Create threads
zactor_t *client = zactor_new (client_task, "Hello, Client");
assert (client);
zactor_t *worker = zactor_new (worker_task, "Hello, Worker");
assert (worker);
zactor_t *broker = zactor_new (broker_task, "Hello, Task");
assert (broker);
char *signal = zstr_recv (client);
printf("signal %s\n", signal);
zstr_free (&signal);
zactor_destroy (&client);
printf("client done\n");
zactor_destroy (&worker);
printf("worker done\n");
zactor_destroy (&broker);
printf("broker done\n");
return 0;
}
//往返演示器
//虽然此示例在单个进程中运行,但这只是为了
//开始和停止示例更容易。客户端任务向
//当它准备好的时候。
#包括
静态空隙
客户端任务(zsock_t*管道,void*参数)
{
断言(streq((char*)args,“你好,客户”);
zsock_信号(管道,0);
zsock_t*客户=zsock_new(ZMQ_经销商);
zsock_connect(客户端)tcp://127.0.0.1:5555");
printf(“设置测试…\n”);
zclock_睡眠(100);
int请求;
int64_t启动;
printf(“同步往返测试…\n”);
开始=zclock_time();
对于(请求=0;请求<10000;请求++){
zstr_发送(客户,“你好”);
zmsg_t*msgh=zmsg_recv(客户);
zmsg_销毁(&msgh);
}
printf(“%d次呼叫/秒”\n“,
(1000*10000)/(int)(zclock_time()-start));
printf(“异步往返测试…\n”);
开始=zclock_time();
对于(请求=0;请求<100000;请求++){
zstr_发送(客户,“你好”);
}
对于(请求=0;请求<100000;请求++){
char*reply=zstr_recv(客户);
zstr_免费(&reply);
}
printf(“%d次呼叫/秒”\n“,
(1000*100000)/(int)(zclock_time()-开始);
zstr_发送(管道,“完成”);
printf(“发送“完成”到管道\n”);
}
//这是工人任务。它所做的只是接收一条消息
//将它按原样弹回来:
静态空隙
工人任务(zsock_t*管道、void*参数)
{
断言(streq((char*)args,“你好,工人”);
zsock_信号(管道,0);
zsock_t*工人=zsock_new(ZMQ_经销商);
zsock_connect(工人)tcp://127.0.0.1:5556");
bool=false;
而(!终止){
zmsg_t*msg=zmsg_recv(工人);
zmsg_发送(&msg),工作人员;
//zstr_send(worker,“hello back”);//表现更好我不知道为什么
}
zsock_销毁(和工人);
}
//下面是代理任务。它使用zmq_代理函数进行切换
//前端和后端之间的消息:
静态空隙
代理任务(zsock_t*pipe,void*args)
{
断言(streq((char*)args,“Hello,Task”);
zsock_信号(管道,0);
//准备我们的代理及其套接字
zactor_t*proxy=zactor_new(zproxy,NULL);
zstr_sendx(代理,“前端”,“经销商”tcp://127.0.0.1:5555“,空);
zsock_wait(代理);
zstr_sendx(代理,“后端”,“经销商”tcp://127.0.0.1:5556“,空);
zsock_wait(代理);
bool=false;
而(!终止){
zmsg_t*msg=zmsg_recv(管道);
如果(!msg)
中断;//中断
char*command=zmsg_popstr(msg);
if(streq(命令,“$TERM”)){
终止=真;
printf(“经纪人收到$TERM\n”);
}
弗里恩(指挥部);
zmsg_销毁(&msg);
}
zactor_销毁(和代理);
}
//最后,这里是主要任务,它启动客户机、工作者和
//代理,然后运行,直到客户端发出停止的信号:
内部主(空)
{
//创建线程
zactor_t*client=zactor_new(客户端任务,“你好,客户端”);
断言(客户);
zactor_t*worker=zactor_new(worker_任务,“你好,worker”);
断言(工人);
zactor_t*broker=zactor_new(broker_任务,“你好,任务”);
断言(经纪人);
char*signal=zstr_recv(客户机);
printf(“信号%s\n”,信号);
zstr_自由(和信号);
zactor_销毁(和客户);
printf(“客户端完成\n”);
zactor_销毁(和工人);
printf(“工作人员完成\n”);
zactor_销毁(和经纪人);
printf(“代理完成”\n);
返回0;
}
让我们一步一步地诊断原样状态:
如果这符合您的期望,您可能希望DLL版本都匹配并且在适当的位置找到
下一步:
可以测试整个马戏团在非阻塞模式下运行,以证明没有其他b
// Round-trip demonstrator
// While this example runs in a single process, that is just to make
// it easier to start and stop the example. The client task signals to
// main when it's ready.
#include <czmq.h>
static void
client_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Client"));
zsock_signal (pipe, 0);
zsock_t *client = zsock_new (ZMQ_DEALER);
zsock_connect (client, "tcp://127.0.0.1:5555");
printf ("Setting up test...\n");
zclock_sleep (100);
int requests;
int64_t start;
printf ("Synchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 10000; requests++) {
zstr_send (client, "hello");
zmsg_t *msgh = zmsg_recv (client);
zmsg_destroy (&msgh);
}
printf (" %d calls/second\n",
(1000 * 10000) / (int) (zclock_time () - start));
printf ("Asynchronous round-trip test...\n");
start = zclock_time ();
for (requests = 0; requests < 100000; requests++) {
zstr_send (client, "hello");
}
for (requests = 0; requests < 100000; requests++) {
char *reply = zstr_recv (client);
zstr_free (&reply);
}
printf (" %d calls/second\n",
(1000 * 100000) / (int) (zclock_time () - start));
zstr_send (pipe, "done");
printf("send 'done' to pipe\n");
}
// Here is the worker task. All it does is receive a message, and
// bounce it back the way it came:
static void
worker_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Worker"));
zsock_signal (pipe, 0);
zsock_t *worker = zsock_new (ZMQ_DEALER);
zsock_connect (worker, "tcp://127.0.0.1:5556");
bool terminated = false;
while (!terminated) {
zmsg_t *msg = zmsg_recv (worker);
zmsg_send (&msg, worker);
// zstr_send (worker, "hello back"); // Give better perf I don't know why
}
zsock_destroy (&worker);
}
// Here is the broker task. It uses the zmq_proxy function to switch
// messages between frontend and backend:
static void
broker_task (zsock_t *pipe, void *args)
{
assert (streq ((char *) args, "Hello, Task"));
zsock_signal (pipe, 0);
// Prepare our proxy and its sockets
zactor_t *proxy = zactor_new (zproxy, NULL);
zstr_sendx (proxy, "FRONTEND", "DEALER", "tcp://127.0.0.1:5555", NULL);
zsock_wait (proxy);
zstr_sendx (proxy, "BACKEND", "DEALER", "tcp://127.0.0.1:5556", NULL);
zsock_wait (proxy);
bool terminated = false;
while (!terminated) {
zmsg_t *msg = zmsg_recv (pipe);
if (!msg)
break; // Interrupted
char *command = zmsg_popstr (msg);
if (streq (command, "$TERM")) {
terminated = true;
printf("broker received $TERM\n");
}
freen (command);
zmsg_destroy (&msg);
}
zactor_destroy (&proxy);
}
// Finally, here's the main task, which starts the client, worker, and
// broker, and then runs until the client signals it to stop:
int main (void)
{
// Create threads
zactor_t *client = zactor_new (client_task, "Hello, Client");
assert (client);
zactor_t *worker = zactor_new (worker_task, "Hello, Worker");
assert (worker);
zactor_t *broker = zactor_new (broker_task, "Hello, Task");
assert (broker);
char *signal = zstr_recv (client);
printf("signal %s\n", signal);
zstr_free (&signal);
zactor_destroy (&client);
printf("client done\n");
zactor_destroy (&worker);
printf("worker done\n");
zactor_destroy (&broker);
printf("broker done\n");
return 0;
}
int czmqMAJOR,
czmqMINOR,
czmqPATCH;
zsys_version ( &czmqMAJOR, &czmqMINOR, &czmqPATCH );
printf( "INF: detected CZMQ( %d, %d, %d )-version",
czmqMAJOR,
czmqMINOR,
czmqPATCH
);
assert ( czmqMAJOR == CZMQ_VERSION_MAJOR & "Major: does not match\n" );
assert ( czmqMINOR == CZMQ_VERSION_MINOR & "Minor: does not match\n" );
assert ( czmqPATCH == CZMQ_VERSION_PATCH & "Patch: does not match\n" );
zsys_info ( "INF: This system's Context() limit is %zu ZeroMQ sockets",
zsys_socket_limit ()
);
// Initialize CZMQ zsys layer; this happens automatically when you create
// a socket or an actor; however this call lets you force initialization
// earlier, so e.g. logging is properly set-up before you start working.
// Not threadsafe, so call only from main thread. Safe to call multiple
// times. Returns global CZMQ context.
CZMQ_EXPORT void *
zsys_init (void);
// Optionally shut down the CZMQ zsys layer; this normally happens automatically
// when the process exits; however this call lets you force a shutdown
// earlier, avoiding any potential problems with atexit() ordering, especially
// with Windows dlls.
CZMQ_EXPORT void
zsys_shutdown (void);
// Configure the number of I/O threads that ZeroMQ will use. A good
// rule of thumb is one thread per gigabit of traffic in or out. The
// default is 1, sufficient for most applications. If the environment
// variable ZSYS_IO_THREADS is defined, that provides the default.
// Note that this method is valid only before any socket is created.
CZMQ_EXPORT void
zsys_set_io_threads (size_t io_threads);
void *aGlobalCONTEXT = zsys_init();
printf( "INF: current state of the global Context()-instance has:\n" );
printf( " ( %d )-IO-threads ready\n", zmq_ctx_get( aGlobalCONTEXT,
ZMQ_IO_THREADS
)
);
printf( " ( %d )-ZMQ_BLOCKY state\n", zmq_ctx_get( aGlobalCONTEXT,
ZMQ_BLOCKY
)
); // may generate -1 in case DLL is << 4.2+
...
// Set interrupt handler; this saves the default handlers so that a
// zsys_handler_reset () can restore them. If you call this multiple times
// then the last handler will take affect. If handler_fn is NULL, disables
// default SIGINT/SIGTERM handling in CZMQ.
CZMQ_EXPORT void
zsys_handler_set (zsys_handler_fn *handler_fn);
// Callback for interrupt signal handler
typedef void (zsys_handler_fn) (int signal_value);