[zeromq-dev] inproc: passing an object pointer between threads causing datarace?? (3.2.2 stable release)

Kah-Chan Low kahchanlow at yahoo.com
Thu Nov 29 16:42:52 CET 2012


Peter,
You're the expert, but I simply am unable to bring myself to agree with you.
Is something wrong with my brain??
When I run the code for real I have not encountered any problem.

OK, let's run through the code for a couple of iteration...

Step 1. Suppose after "new int", variable "n" is pointing to memory location 0x12345
step 2. zmq_socket.send() is called, passing the on-the-stack buffer "n" containing 0x12345 of 4-bytes (assuming 32-bit address).
Step 3. In zmq_send(), memcpy copies 4 bytes starting from the buffer.  So the value 0x12345 is copied into the data part of zmq_msg_t msg.
step 4. s_sendmsg() is called on msg, asynchronously send off the value 0x1234 stored in  zmq_msg_t msg.
Step 5. Next iteration. n is pointing to a new memory location, say 0x56789a, and we start the process all over again.


I simply don't see how the on-the-stack address &n is queued anywhere...

n is updated at the beginning of each allocation but the 0x12345 is still a valid memory location containing the value 6.
I really don't see anything wrong with the code...


for (...) {
  int *n = new int;
  *n = 4;
  *n += 2;
  zmq_socket.send(&n, sizeof(n));
}


Doesn't zmq_send(), which is called by socket_t::send(), make a copy of whatever message that is passed in before returning?
So a different pointer gets passed in and copied in each iteration.  What is wrong with doing that?

int zmq_send (void *s_, const void *buf_, size_t len_, int flags_)
{
    if (!s_ || !((zmq::socket_base_t*) s_)->check_tag ()) {
        errno = ENOTSOCK;
        return -1;
    }
   
 zmq_msg_t msg;
    int rc = zmq_msg_init_size (&msg, len_);
    if (rc != 0)
        return -1;
    memcpy (zmq_msg_data (&msg), buf_, len_);  // isn't copying done here?

    zmq::socket_base_t *s = (zmq::socket_base_t *) s_;
    rc = s_sendmsg (s, &msg, flags_);
    if (unlikely (rc < 0)) {
        int err = errno;
        int rc2 = zmq_msg_close (&msg);
        errno_assert (rc2 == 0);
        errno = err;
        return -1;
    }

    //  Note the optimisation here. We don't close the msg object as it is
    //  empty anyway.
 This may change when implementation of zmq_msg_t changes.
    return rc;
}

________________________________
 From: Pieter Hintjens <ph at imatix.com>
To: Kah-Chan Low <kahchanlow at yahoo.com> 
Cc: ZMQ ZMQ <zeromq-dev at lists.zeromq.org> 
Sent: Thursday, November 29, 2012 9:50 AM
Subject: Re: [zeromq-dev] inproc: passing an object pointer between threads causing datarace?? (3.2.2 stable release)
 
On Thu, Nov 29, 2012 at 3:25 PM, Kah-Chan Low <kahchanlow at yahoo.com> wrote:

> Doesn't zmq_send(), which is called by socket_t::send(), make a copy of
> whatever message that is passed in before returning?

It takes the buffer you provide and queues that address for sending.
It's confusing you because you think the pointer is passed by value
whereas you are passing its address, precisely as if it was a buffer.
This is a fairly common error for beginners, to pass a buffer that is
deallocated before the send completes.

(I've not tried to reproduce it but this is what I believe is happening.)

Try just sending one pointer (not in a loop).

-Piieter
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.zeromq.org/pipermail/zeromq-dev/attachments/20121129/80343809/attachment.htm>


More information about the zeromq-dev mailing list