int main(int argc, const char **argv) {
    try {
        if (argc != 5) {
            std::cerr <<
                "Usage: " << argv[0] << " CONNECTION-URL AMQP-ADDRESS MESSAGE-COUNT THREAD-COUNT\n"
                "CONNECTION-URL: connection address, e.g.'amqp://127.0.0.1'\n"
                "AMQP-ADDRESS: AMQP node address, e.g. 'examples'\n"
                "MESSAGE-COUNT: number of messages to send\n"
                "THREAD-COUNT: number of sender/receiver thread pairs\n";
            return 1;
        }

        const char *url = argv[1];
        const char *address = argv[2];
        int n_messages = atoi(argv[3]);
        int n_threads = atoi(argv[4]);
        int count = n_messages * n_threads;

        // Total messages to be received, multiple receiver threads will decrement this.
        std::atomic_int remaining;
        remaining.store(count);

        // Run the proton container
        proton::container container;
        auto container_thread = std::thread([&]() { container.run(); });

        // A single sender and receiver to be shared by all the threads
        sender send(container, url, address);
        receiver recv(container, url, address);

        // Start receiver threads, then sender threads.
        // Starting receivers first gives all receivers a chance to compete for messages.
        std::vector<std::thread> threads;
        threads.reserve(n_threads*2); // Avoid re-allocation once threads are started
        for (int i = 0; i < n_threads; ++i)
            threads.push_back(std::thread([&]() { receive_thread(recv, remaining); }));
        for (int i = 0; i < n_threads; ++i)
            threads.push_back(std::thread([&]() { send_thread(send, n_messages); }));

        // Wait for threads to finish
        for (auto& t : threads) t.join();
        send.close();
        recv.close();
        container_thread.join();
        if (remaining > 0)
            throw std::runtime_error("not all messages were received");
        std::cout << count << " messages sent and received" << std::endl;

        return 0;
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }
    return 1;
}
Пример #2
0
void
hastd_secondary(struct hast_resource *res, struct nv *nvin)
{
	sigset_t mask;
	pthread_t td;
	pid_t pid;
	int error, mode, debuglevel;

	/*
	 * Create communication channel between parent and child.
	 */
	if (proto_client(NULL, "socketpair://", &res->hr_ctrl) < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR,
		    "Unable to create control sockets between parent and child");
	}
	/*
	 * Create communication channel between child and parent.
	 */
	if (proto_client(NULL, "socketpair://", &res->hr_event) < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR,
		    "Unable to create event sockets between child and parent");
	}

	pid = fork();
	if (pid < 0) {
		KEEP_ERRNO((void)pidfile_remove(pfh));
		pjdlog_exit(EX_OSERR, "Unable to fork");
	}

	if (pid > 0) {
		/* This is parent. */
		proto_close(res->hr_remotein);
		res->hr_remotein = NULL;
		proto_close(res->hr_remoteout);
		res->hr_remoteout = NULL;
		/* Declare that we are receiver. */
		proto_recv(res->hr_event, NULL, 0);
		/* Declare that we are sender. */
		proto_send(res->hr_ctrl, NULL, 0);
		res->hr_workerpid = pid;
		return;
	}

	gres = res;
	mode = pjdlog_mode_get();
	debuglevel = pjdlog_debug_get();

	/* Declare that we are sender. */
	proto_send(res->hr_event, NULL, 0);
	/* Declare that we are receiver. */
	proto_recv(res->hr_ctrl, NULL, 0);
	descriptors_cleanup(res);

	descriptors_assert(res, mode);

	pjdlog_init(mode);
	pjdlog_debug_set(debuglevel);
	pjdlog_prefix_set("[%s] (%s) ", res->hr_name, role2str(res->hr_role));
	setproctitle("%s (%s)", res->hr_name, role2str(res->hr_role));

	PJDLOG_VERIFY(sigemptyset(&mask) == 0);
	PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);

	/* Error in setting timeout is not critical, but why should it fail? */
	if (proto_timeout(res->hr_remotein, 2 * HAST_KEEPALIVE) < 0)
		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
	if (proto_timeout(res->hr_remoteout, res->hr_timeout) < 0)
		pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");

	init_local(res);
	init_environment();

	if (drop_privs(res) != 0)
		exit(EX_CONFIG);
	pjdlog_info("Privileges successfully dropped.");

	/*
	 * Create the control thread before sending any event to the parent,
	 * as we can deadlock when parent sends control request to worker,
	 * but worker has no control thread started yet, so parent waits.
	 * In the meantime worker sends an event to the parent, but parent
	 * is unable to handle the event, because it waits for control
	 * request response.
	 */
	error = pthread_create(&td, NULL, ctrl_thread, res);
	PJDLOG_ASSERT(error == 0);

	init_remote(res, nvin);
	event_send(res, EVENT_CONNECT);

	error = pthread_create(&td, NULL, recv_thread, res);
	PJDLOG_ASSERT(error == 0);
	error = pthread_create(&td, NULL, disk_thread, res);
	PJDLOG_ASSERT(error == 0);
	(void)send_thread(res);
}