I'm attempting to solve a multi-threaded socket use issue in my pthreaded Linux code, and I think it might be insoluble, given my requirements. Can you let me know whether you agree?
The problem is this:
I have multiple pthreads writing to a single SOCK_STREAM (TCP) socket (set for non-blocking IO). Each thread is attempting to write a single "message" at a time, and message data from different threads must not be interleaved.
I am prepared for send() to return EWOULDBLOCK/EAGAIN in a minority of cases (in which case I just defer the write of the message to an asynchronous thread using a mutex protected queuing structure)
I cannot get mutexes on these foreground writing threads (apart from the EWOULDBLOCK/EAGAIN cases), as the implied cache flushes give me an unacceptable CPU impact (this also means no use of other synchronization objects to work around the problem, such as atomic integers).
As far as I know, I cannot guarantee that send() won't decide to write some, but not all of any given message, thus resulting in (potentially) interleaved data
Is this problem insoluble? Is there any way to force send() to either buffer the entire message or none of it (when using non-blocking IO)?
Thanks!
I have multiple pthreads writing to a single SOCK_STREAM (TCP) socket (set for non-blocking IO). Each thread is attempting to write a single "message" at a time, and message data from different threads must not be interleaved.
TCP is a byte stream, it has no concept of "messages" like UDP does. You MUST synchronize access to a TCP socket, such as with a mutex, to avoid interweaving the "messages".
I am prepared for send() to return EWOULDBLOCK/EAGAIN in a minority of cases (in which case I just defer the write of the message to an asynchronous thread using a mutex protected queuing structure)
In which case, you will likely need to send MOST/ALL of your "messages" through that same queue, so it can ensure that they get sent in the proper order. If you start sending a "message" directly and it gets an EWOULDBLOCK/EAGAIN error, the remaining unsent data for that "message", and all subsequent "messages", MUST be queued until the queue is emptied. Whenever the socket is writable, send whatever is in the queue, removing only what is successfully sent, and repeating as needed until the queue is emptied. Only then can you safely send new "messages" directly until another EWOULDBLOCK/EAGAIN error is reported. But no matter what, you will still need to synchronize the sends so only 1 "message" is being sent at a time, whether directly or from the queue.
For example, you can do something like this (pseudo code):
void sendMsg(message msg)
{
lock(&mutex);
if (!queue.empty()) {
queue.add(&msg, sizeof(msg));
}
else
{
byte *ptr = &msg;
size_t size = sizeof(msg);
do {
int sent = send(sock, ptr, size, 0);
if (sent == -1) {
if (errno == EINTR) continue;
queue.add(ptr, size);
break;
}
ptr += sent;
size -= sent;
}
while (size > 0);
}
unlock(&mutex);
}
void socketIsWritable()
{
lock(&mutex);
while (!queue.empty()) {
int sent = send(sock, queue.data(), queue.size(), 0);
if (sent == -1) {
if (errno == EINTR) continue;
break;
}
queue.remove(sent);
}
unlock(&mutex);
}
I cannot get mutexes on these foreground writing threads (apart from the EWOULDBLOCK/EAGAIN cases), as the implied cache flushes give me an unacceptable CPU impact (this also means no use of other synchronization objects to work around the problem, such as atomic integers).
Synchronizing access to the socket is the only way to ensure the integrity of the "messages" you want to send. Which does mean there will be a small bottleneck in your communications. You can't begin sending a new "message" until a previous "message" has finished being sent in full.
As far as I know, I cannot guarantee that send() won't decide to write some, but not all of any given message, thus resulting in (potentially) interleaved data
Correct.
Is there any way to force send() to either buffer the entire message or none of it (when using non-blocking IO)?
No. And even if it could, that would still not prevent against interweaving when multiple threads try to call send() at the same time. You need to handle the necessary buffering in your own code.
Related
I want to implement a simple notification protocol using TCP sockets. The server will write a byte to a socket to notify the client, and the client reads from the socket, waiting until some data arrives, at which point it can return from the read call and perform some work.
while (1) {
/* Wait for any notifications */
char buf[32];
if (read(fd, buf, sizeof(buf)) <= 0) {
break;
}
/* Received notification */
do_work();
}
My question is, is read guaranteed to return as soon as any data is available to read, or is the kernel allowed to keep waiting until some condition is met (e.g. some minimum number of bytes received, not necessarily the count which I pass into read) before it returns from the read call? If the latter is true, is there a flag that will disable that behavior?
I am aware that I could use the O_NONBLOCK flag and call read in a loop, but the purpose of this is to use as little CPU time as possible.
There are multiple implicit questions here:
Is read guaranteed to return immediately or shortly after a relevant event?
No. The kernel is technically allowed to make you wait as long as it wants.
In practice, it'll return immediately (modulo rescheduling delays).
This is true for poll and O_NONBLOCK as well. Linux is not a realtime OS, and offers no hard timing guarantees, just its best effort.
Is read allowed to wait indefinitely for multiple bytes to become available?
No, this would cause deadlocks. read needs to be able to return with a single byte, even if there are no guarantees about when it will do so.
In practice, Linux makes the same effort for 1 byte as it does for 1,048,576.
Is sending a single byte on a socket a practical way of waking up a remote process as soon as possible?
Yes, your example is perfectly fine.
My program like this:
func handle(conn net.Conn) {
msg := "hello, world!"
for i:= 0; i< 100000; i++ {
go func() {
err := write(conn, msg)
}
}
}
func write(conn net.Conn, msg string) error {
mlen := fmt.Sprintf("%04d", len(msg))
_, err := conn.Write([]byte(mlen + msg))
return err
}
The program will run 100000 goroutines at same time, and all goroutines will send message to the same connection。
I am doubt that server will receive error message like "hellohelloworldworld", but there is no problem when the program run in my Ubuntu 14.04LTS.
So, Do multiple goroutine will invoke a method on a Conn simultaneously?
=========================================================================
How can I keep the Write method atomic?
The documentation states:
Multiple goroutines may invoke methods on a Conn simultaneously.
There is no mention of whether each individual write is atomic. While the current implementation may ensure that each call to Write happens completely before the next call can begin, there is no guarantee in the language specification.
This answer implies writes are atomic.
Specifically implementors of the io.Write interface are required to return an error if a partial write occurs. net.Conn handles this on unix by acquiring a lock and calling write in a loop until the whole buffer is written. On Windows it calls WSASend which guarantees to send the whole buffer unless an error occurs. But the docs do have this warning:
The order of calls made to WSASend is also the order in which the
buffers are transmitted to the transport layer. WSASend should not be
called on the same stream-oriented socket concurrently from different
threads, because some Winsock providers may split a large send request
into multiple transmissions, and this may lead to unintended data
interleaving from multiple concurrent send requests on the same
stream-oriented socket.
Which means it wouldn't necessarily be atomic, unless Go acquires a mutex - which it does.
So basically it is atomic in practice. It is conceivable that an implementation could define thread-safety as just not crashing and allow interleaved writes by unlocking the mutex around calls to write (or not acquiring it at all on windows.) That doesn't make sense to me though, and the developers have clearly shown the opposite intent.
Has any one tried to create a socket in non blocking mode and use a dedicated thread to write to the socket, but use the select system call to identify if data is available to read data.
if the socket is non blocking, the write call will return immediately and the application will not know the status of the write (if it passed or failed).
is there a way of knowing the status of the write call without having to block on it.
Has any one tried to create a socket in non blocking mode and use a dedicated thread to write to the socket, but use the select system call to identify if data is available to read data.
Yes, and it works fine. Sockets are bi-directional. They have separate buffers for reading and writing. It is perfectly acceptable to have one thread writing data to a socket while another thread is reading data from the same socket at the same time. Both threads can use select() at the same time.
if the socket is non blocking, the write call will
return immediately and the application will not
know the status of the write (if it passed or failed).
The same is true for blocking sockets, too. Outbound data is buffered in the kernel and transmitted in the background. The difference between the two types is that if the write buffer is full (such as if the peer is not reading and acking data fast enough), a non-blocking socket will fail to accept more data and report an error code (WSAEWOULDBLOCK on Windows, EAGAIN or EWOULDBLOCK on other platforms), whereas a blocking socket will wait for buffer space to clear up and then write the pending data into the buffer. Same thing with reading. If the inbound kernel buffer is empty, a non-blocking socket will fail with the same error code, whereas a blocking socket will wait for the buffer to receive data.
select() can be used with both blocking and non-blocking sockets. It is just more commonly used with non-blocking sockets than blocking sockets.
is there a way of knowing the status of the write
call without having to block on it.
On non-Windows platforms, about all you can do is use select() or equivalent to detect when the socket can accept new data before writing to it. On Windows, there are ways to receive a notification when a pending read/write operation completes if it does not finish right away.
But either way, outbound data is written into a kernel buffer and not transmitted right away. Writing functions, whether called on blocking or non-blocking sockets, merely report the status of writing data into that buffer, not the status of transmitting the data to the peer. The only way to know the status of the transmission is to have the peer explicitly send back a reply message once it has received the data. Some protocols do that, and others do not.
is there a way of knowing the status of the write call without having
to block on it.
If the result of the write call is -1, then check errno to for EAGAIN or EWOULDBLOCK. If it's one of those errors, then it's benign and you can go back to waiting on a select call. Sample code below.
int result = write(sock, buffer, size);
if ((result == -1) && ((errno == EAGAIN) || (errno==EWOULDBLOCK)) )
{
// write failed because socket isn't ready to handle more data. Try again later (or wait for select)
}
else if (result == -1)
{
// fatal socket error
}
else
{
// result == number of bytes sent.
// TCP - May be less than the number of bytes passed in to write/send call.
// UDP - number of bytes sent (should be the entire thing)
}
I am in the same situation as this guy, but I don't quite understand the answer.
The problem:
Thread 1 calls accept on a socket, which is blocking.
Thread 2 calls close on this socket.
Thread 1 continues blocking. I want it to return from accept.
The solution:
what you should do is send a signal to the thread which is blocked in
accept. This will give it EINTR and it can cleanly disengage - and
then close the socket. Don't close it from a thread other than the one
using it.
I don't get what to do here -- when the signal is received in Thread 1, accept is already blocking, and will continue to block after the signal handler has finished.
What does the answer really mean I should do?
If the Thread 1 signal handler can do something which will cause accept to return immediately, why can't Thread 2 do the same without signals?
Is there another way to do this without signals? I don't want to increase the caveats on the library.
Instead of blocking in accept(), block in select(), poll(), or one of the similar calls that allows you to wait for activity on multiple file descriptors and use the "self-pipe trick". All of the file descriptors passed to select() should be in non-blocking mode. One of the file descriptors should be the server socket that you use with accept(); if that one becomes readable then you should go ahead and call accept() and it will not block. In addition to that one, create a pipe(), set it to non-blocking, and check for the read side becoming readable. Instead of calling close() on the server socket in the other thread, send a byte of data to the first thread on the write end of the pipe. The actual byte value doesn't matter; the purpose is simply to wake up the first thread. When select() indicates that the pipe is readable, read() and ignore the data from the pipe, close() the server socket, and stop waiting for new connections.
The accept() call will return with error code EINTR if a signal is caught before a connection is accepted. So check the return value and error code then close the socket accordingly.
If you wish to avoid the signal mechanism altogether, use select() to determine if there are any incoming connections ready to be accepted before calling accept(). The select() call can be made with a timeout so that you can recover and respond to abort conditions.
I usually call select() with a timeout of 1000 to 3000 milliseconds from a while loop that checks for an exit/abort condition. If select() returns with a ready descriptor I call accept() otherwise I either loop around and block again on select() or exit if requested.
Call shutdown() from Thread 2. accept will return with "invalid argument".
This seems to work but the documentation doesn't really explain its operation across threads -- it just seems to work -- so if someone can clarify this, I'll accept that as an answer.
Just close the listening socket, and handle the resulting error or exception from accept().
I believe signals can be used without increasing "the caveats on the library". Consider the following:
#include <pthread.h>
#include <signal.h>
#include <stddef.h>
static pthread_t thread;
static volatile sig_atomic_t sigCount;
/**
* Executes a concurrent task. Called by `pthread_create()`..
*/
static void* startTask(void* arg)
{
for (;;) {
// calls to `select()`, `accept()`, `read()`, etc.
}
return NULL;
}
/**
* Starts concurrent task. Doesn't return until the task completes.
*/
void start()
{
(void)pthread_create(&thread, NULL, startTask, NULL);
(void)pthread_join(thread);
}
static void noop(const int sig)
{
sigCount++;
}
/**
* Stops concurrent task. Causes `start()` to return.
*/
void stop()
{
struct sigaction oldAction;
struct sigaction newAction;
(void)sigemptyset(&newAction.sa_mask);
newAction.sa_flags = 0;
newAction.sa_handler = noop;
(void)sigaction(SIGTERM, &newAction, &oldAction);
(void)pthread_kill(thread, SIGTERM); // system calls return with EINTR
(void)sigaction(SIGTERM, &oldAction, NULL); // restores previous handling
if (sigCount > 1) // externally-generated SIGTERM was received
oldAction.sa_handler(SIGTERM); // call previous handler
sigCount = 0;
}
This has the following advantages:
It doesn't require anything special in the task code other than normal EINTR handling; consequently, it makes reasoning about resource leakage easier than using pthread_cancel(), pthread_cleanup_push(), pthread_cleanup_pop(), and pthread_setcancelstate().
It doesn't require any additional resources (e.g. a pipe).
It can be enhanced to support multiple concurrent tasks.
It's fairly boilerplate.
It might even compile. :-)
I'm trying to learn boost::asio for socket/networking programming. I'm trying to send some simple data from the client to the server.
Let me say first of all that I am intentionally using synchronous, blocking code, as opposed to asynchronous, non-blocking code, because I'm using multithreading (with the pthreads library) in addition to this.
The client is successfully calling boost::asio::write(). I've gone so far as to not only try and catch any exceptions thrown by boost::asio::write(), but to also check the boost::system::error_code value, which gives a message "The operation has been completed successfully" or something to that effect.
My read() code looks like this:
#define MAX_MESSAGE_SIZE 10000 // in bytes
void* receivedData = malloc(MAX_MESSAGE_SIZE);
try
{
boost::asio::read(*sock, boost::asio::buffer(receivedData, MAX_MESSAGE_SIZE));
}
catch (std::exception &e)
{
std::cout << "Exception thrown by boost::read() in receiveMessage(): " << e.what() << "\n";
delete receivedData;
receivedData = NULL;
return false;
}
Despite write() being successfully executed on the other end, and both client and server agreeing that a connection has been established at this point, read() never returns. The only case in which it returns for me is if I manually close the client application, at which point (as one would expect), the read() call throws an exception stating that the client has forcibly closed the connection.
Does it have anything to do with io_service.run()? In my googling to debug this, I ran across some mentions of run(), and what I've implicitly gathered from those posts is that run() processes the "work", which I take to mean that it does the actual sending and receiving, and that write() and read() are just means of queuing up a send and checking for what packets have already been sent in and "approved", so to speak, by io_service.run(). Please correct me if I'm wrong, as the Boost documentation says little more than "Run the io_service's event processing loop."
I'm following the boost::asio tutorial ( http://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/tutorial/tutdaytime1.html ) which makes absolutely no mention of run(), so maybe I'm completely on the wrong track here and run() isn't necessary at all?
Either way, just now I made another change to my code to see if anything would change (it didn't): in both my client and server, I set up a thread for the following function (to call io_service.run() repeatedly throughout the application's duration to see if not doing so is what was causing the problem):
void* workerThread(void* nothing)
{
while(1)
{
io_service.run();
Sleep(10); // just keeping my CPU from overheating in this infinite loop
}
}
But as stated above, that didn't affect the performance at all.
What am I missing here? Why is read() never returning, even after the other end's write() has been executed successfully?
Thanks in advance.
Note that the read you are using will block until the buffer is full or an error occurs - so it will only return when it has received 10000 bytes.
Consider using read_some or using a completion condition with read instead.