This is the mail archive of the mailing list for the libstdc++ project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

BUG in libstdc++-2.8.1; also 2.90.4 (libio in combination with pthreads + sockets)

The istream input methods seem to contain a bug that causes
multithreaded programs to deadlock: After using one of the
functions listed below in one thread, using
others in other threads blocks. This seems to be due to the
above functions doing a flockfile() system call without
doing funlockfile().

  istream& istream::get(char& c)
  istream& istream::ignore(int n, int delim)
  istream& istream::read(char *s, streamsize n)
  istream& istream::operator>>(char& c)
  istream::operator>> (char* ptr)
  static int read_int(istream& stream, unsigned LONGEST& val, int& neg)
  istream& istream::operator>>(long double& x)
  istream& istream::operator>>(double& x)
  istream& istream::operator>>(float& x)
  istream& istream::operator>>(register streambuf* sbuf)
  ** maybe some more **

Is this a known problem?
What is the purpose of unsing flockfile() / funlockfile() in libio?
  IMHO synchronizing I/O between threads should be left to the user.
How do the _IO_cleanup_region_start and _IO_cleanup_region_end calls
  work? where are they documented?

An example demonstrating the problem and how it can be fixed is

To compile:
  > g++ -lpthread -o sockio
  > g++ -lpthread -DIOSTREAM_GET_FIX -o sockio

========================== ==========================
#include <string.h>
#include <pthread.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <iostream.h>


istream& istream::get(char& c)
    if (ipfx1()) {
  int ch = _strbuf->sbumpc();
  if (ch == EOF) {
    _gcount = 0;
  else {
    c = (char)ch;
    _gcount = 1;
      _gcount = 0;
  isfx();                                   // <== this line added
    return *this;

// --- Create a server socket etc.
int serve()
  int server_sock = socket(AF_INET, SOCK_STREAM, 0);

  const int Yes = 1;
  setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &Yes, sizeof(Yes));

  struct sockaddr_in server_addr;
  memset(&server_addr, 0, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(3456);
  bind(server_sock, (struct sockaddr *)&server_addr,

  listen(server_sock, 1);

  return server_sock;

// --- Accept a client connection
int accept_client(int server_sock)
  struct sockaddr client_addr;
  unsigned int addr_len = sizeof(client_addr);
  return accept(server_sock, &client_addr, &addr_len);

istream *is;
ostream *os;

// --- Thread does some I/O
void *IO_thread(void *)
  (*os) << "Give me another line: " << endl;

  char c;
  while ((*is).get(c) && (*os).put(c) && c!='\n')
    /* nothing */;

  return NULL;

int main(void)
  int server_sock = serve();
  int client_sock = accept_client(server_sock);

  // --- Attach socket to iostream

  // (one filebuf and iostream doesn't work for sockets:
  //  the read and write buffer would get synchronized)

  filebuf read_buffer(client_sock);
  filebuf write_buffer(client_sock);
  is = new istream(&read_buffer);
  os = new ostream(&write_buffer);

  // --- Do some I/O
  (*os) << "Give me a line: " << endl;

  char c;
  while ((*is).get(c) && (*os).put(c) && c!='\n')
    /* nothing */;

  // --- Start thread that does some I/O
  pthread_t io_thread;
  pthread_create(&io_thread, NULL, IO_thread, NULL);
  pthread_join(io_thread, NULL);  // wait for thread to die

  (*os) << "Thread died" << endl;

  delete is;
  delete os;

 Andreas Gruenbacher, Vienna University of Technology
 Contact information:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]