[英]ZeroMQ crashed when created workers with std::thread
I am porting the lbbroker.c example from the ZeroMQ Guide Book to the higher level API czmq
.我正在将 ZeroMQ 指南中的lbbroker.c 示例移植到更高级别的 API czmq
。
For some reason, a std::thread
that creates and connects to an endpoint using a zsock
always crashed.出于某种原因,使用zsock
创建并连接到端点的std::thread
总是崩溃。 Here is the code for load-balancing broker written using C++:下面是使用 C++ 编写的负载均衡代理的代码:
// Load-balancing broker
// Demonstrates use of the CZMQ API
#include <czmq.h>
#include <cstdio>
#include <thread>
#include <iostream>
#include <vector>
#define NBR_CLIENTS 10
#define NBR_WORKERS 3
#define WORKER_READY "READY" // Signals worker is ready
// Basic request-reply client using REQ socket
//
void client_task()
{
std::cout << "Start client...\n";
zsock_t *client = zsock_new_req("tcp://*:5672");
// zsock_t *client = zsock_new_req("ipc://frontend.ipc");
std::cout << "Client connect...\n";
// zsock_connect(client, "ipc://frontend.ipc");
// Send request, get reply
std::cout << "Client send HELLO\n";
zstr_send(client, "HELLO");
char *reply = zstr_recv(client);
if (reply) {
printf("Client: %s\n", reply);
free(reply);
}
}
// Worker using REQ socket to do load-balancing
//
void worker_task()
{
std::cout << "Start work task...\n";
zsock_t *worker = zsock_new(ZMQ_REQ);
#if (defined (WIN32))
// worker = zsock_new_req("tcp://localhost:5673"); // backend
#else
// worker = zsock_new_req("ipc://backend.ipc");
#endif
std::cout << "Worker connect\n";
zsock_connect(worker, "tcp::/localhost:5673");
// zsock_connect(worker, "ipc://backend.ipc");
// Tell broker we're ready for work
zframe_t *frame = zframe_new(WORKER_READY, strlen(WORKER_READY));
zframe_send(&frame, worker, 0);
// Process messages as they arrive
while (true) {
zmsg_t *msg = zmsg_recv(worker);
if (!msg)
break; // Interrupted
zframe_print(zmsg_last(msg), "Worker: ");
zframe_reset(zmsg_last(msg), "OK", 2);
zmsg_send(&msg, worker);
}
}
// .split main task
// Now we come to the main task. This has the identical functionality to
// the previous {{lbbroker}} broker example, but uses CZMQ to start child
// threads, to hold the list of workers, and to read and send messages:
int main(void)
{
zsock_t *frontend = zsock_new_router("tcp://*:5672");
zsock_t *backend = zsock_new_router ("tcp://*:5673");
// zsock_t *frontend = zsock_new_router("ipc://frontend.ipc");
// zsock_t *backend = zsock_new_router ("ipc://backend.ipc");
// printf("Create server threads");
for (int worker_nbr = 0; worker_nbr < NBR_WORKERS; worker_nbr++) {
std::thread t(worker_task);
std::cout << "Created worker...\n";
// pthread_t worker;
// pthread_create(&worker, NULL, worker_task, (void *)(intptr_t)worker_nbr);
}
int client_nbr;
std::cout << "Create client threads\n";
for (client_nbr = 0; client_nbr < NBR_CLIENTS; client_nbr++) {
std::thread t(client_task);
// pthread_t client;
// printf("Create client thread %d", client_nbr);
// pthread_create(&client, NULL, client_task, (void *)(intptr_t)client_nbr);
}
// Queue of available workers
zlist_t *workers = zlist_new();
// .split main load-balancer loop
// Here is the main loop for the load balancer. It works the same way
// as the previous example, but is a lot shorter because CZMQ gives
// us an API that does more with fewer calls:
while (true) {
zmq_pollitem_t items[] = {
{ backend, 0, ZMQ_POLLIN, 0 },
{ frontend, 0, ZMQ_POLLIN, 0 }
};
std::cout << "Running\n";
// Poll frontend only if we have available workers
int rc = zmq_poll(items, zlist_size(workers) ? 2 : 1, -1);
if (rc == -1)
break; // Interrupted
// Handle worker activity on backend
if (items[0].revents & ZMQ_POLLIN) {
// Use worker identity for load-balancing
zmsg_t *msg = zmsg_recv(backend);
if (!msg)
break; // Interrupted
#if 0
// zmsg_unwrap is DEPRECATED as over-engineered, poor style
zframe_t *identity = zmsg_unwrap(msg);
#else
zframe_t *identity = zmsg_pop(msg);
zframe_t *delimiter = zmsg_pop(msg);
zframe_destroy(&delimiter);
#endif
zlist_append(workers, identity);
// Forward message to client if it's not a READY
zframe_t *frame = zmsg_first(msg);
if (memcmp(zframe_data(frame), WORKER_READY, strlen(WORKER_READY)) == 0) {
zmsg_destroy(&msg);
} else {
zmsg_send(&msg, frontend);
if (--client_nbr == 0)
break; // Exit after N messages
}
}
if (items[1].revents & ZMQ_POLLIN) {
// Get client request, route to first available worker
zmsg_t *msg = zmsg_recv(frontend);
if (msg) {
#if 0
// zmsg_wrap is DEPRECATED as unsafe
zmsg_wrap(msg, (zframe_t *)zlist_pop(workers));
#else
zmsg_pushmem(msg, NULL, 0); // delimiter
zmsg_push(msg, (zframe_t *)zlist_pop(workers));
#endif
zmsg_send(&msg, backend);
}
}
}
// When we're done, clean up properly
while (zlist_size(workers)) {
zframe_t *frame = (zframe_t *)zlist_pop(workers);
zframe_destroy(&frame);
}
zlist_destroy(&workers);
zsock_destroy(&frontend);
zsock_destroy(&backend);
return 0;
}
You can compile it with g++ lbbroker.cpp -o lbbroker -lzmq -lpthread
.您可以使用g++ lbbroker.cpp -o lbbroker -lzmq -lpthread
编译它。 It compiled successfully, however, when running, I got an exception and a core dumped:它编译成功,但是,在运行时,我遇到了一个异常并转储了一个核心:
Created worker...
terminate called without an active exception
Start work task...
aborted (core dumped)
It crashed in the worker_task
function.它在worker_task
function 中崩溃。 According to GDB, it seems 1 thread successfully created and then the program crashed.根据 GDB,似乎 1 个线程成功创建,然后程序崩溃。 The C version works fine. C 版本工作正常。
C++ has destructors which are called at the end of the scope where the variable was declared. C++ 具有在声明变量的 scope 末尾调用的析构函数。
In the case of std::thread
, if the destructor is called with a joinable thread, std::terminate
will be called.在std::thread
的情况下,如果使用可连接线程调用析构函数,则将调用std::terminate
。 You are supposed to decide whether you want to join
the thread or detach
it before you arrive to the destructor.您应该在到达析构函数之前决定是要join
线程还是detach
线程。
So either you detach the threads (and therefore they will run free without an easy way to wait for them to finish), or you increase the lifetime of the objects and join them later on.因此,要么分离线程(因此它们将自由运行,无需简单的方法等待它们完成),要么增加对象的生命周期并稍后加入它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.