luv interleaved socket writes

21 views
Skip to first unread message

Wes Chow

unread,
Jul 17, 2015, 5:55:23 PM7/17/15
to lu...@googlegroups.com
Apologies if this isn't the right place for a luv question...

If I have two coroutines which each simultaneously do two socket:write operations to the same socket, s:

s:write("foo")
s:write("bar")

I assume that there's a possibility the writes get interleaved. Ie, it's possible that "foofoobarbar" goes out on the socket, and that it might also be possible that "foobarfoobar" goes out.

However, if I do this in two coroutines simultaneously:

s:write("foobar")

Am I guaranteed that data will go out as "foobarfoobar"? Or is it still possible that data gets interleaved within two write calls?

Thanks,
Wes

Tim Caswell

unread,
Jul 17, 2015, 10:58:50 PM7/17/15
to lu...@googlegroups.com

Luv is still single threaded.  I'm pretty sure that the libuv writes are put in a queue.  Your strings will never get chopped up even if another coroutine tries to write to the same socket.

--
You received this message because you are subscribed to the Google Groups "luvit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to luvit+un...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tim Caswell

unread,
Jul 17, 2015, 11:22:59 PM7/17/15
to lu...@googlegroups.com
Now that I have a proper keyboard, let me explain a little better.

I assume that since you're using luv and a write method, you're talking about the uv.write function in luv.  This is non-blocking and coroutines have nothing to do with it.  If you do s:write("a") and s:write("b") in a coroutine, it won't yield for either one, but rather will put both strings on the socket's write queue.  The coroutine will then move on and finish without waiting for the data to actually write and flush.  Then your second coroutine will run and do the same thing.

So actually, the first case is guaranteed to output "abab" and not "aabb" since there is nothing to cause the first coroutine to yield.  The two coroutines never run concurrently, just one and then the other.

Now if you were using some coroutine aware stream like the write function in the coro-net package on lit things would be different.  As you're guessed, the first write would cause the coroutine to yield and not resume till the data has been flushed.  Then the second coroutine would run and do the same thing.  Since the data goes in a fifo queue, the first coroutine would most likely unblock first.  Assuming that your writes are large enough to cause libuv to wait for each write to flush your output will be "aabb" since the two coroutines are running concurrently with cooperative multithreading.

A common pattern I use to wait for callback based APIs is as follows:

    local function write(socket, data)
      local thread = coroutine.running()
      socket:write(data, function (err)
        assert(coroutine.yield(thread, not err, err))
      end)
      return coroutine.yield()
    end

The basic idea is to yield the coroutine whenever we're waiting on a callback and then to resume once it happens.  We rearrange the result values to lua assert friendly value, error instead of the node-style callback(err, data).

Tim Caswell

unread,
Jul 17, 2015, 11:24:37 PM7/17/15
to lu...@googlegroups.com
That should be assert(coroutine.resume(thread, not err, err)) in the middle, sorry for the typo.  We want to yield after starting the non-blocking call and resume after the callback gets called.

You'll need special care for functions that may call their callback before returning (aka zalgo functions).

Wes Chow

unread,
Jul 18, 2015, 7:27:43 AM7/18/15
to lu...@googlegroups.com

That's all very helpful, thanks.

Wes

You received this message because you are subscribed to a topic in the Google Groups "luvit" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/luvit/4NoWnkwIGKQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to luvit+un...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages