This is the mail archive of the
libstdc++@sourceware.cygnus.com
mailing list for the libstdc++ project.
BUG in libstdc++-2.8.1; also 2.90.4 (libio in combination with pthreads + sockets)
- To: libstdc++@sourceware.cygnus.com
- Subject: BUG in libstdc++-2.8.1; also 2.90.4 (libio in combination with pthreads + sockets)
- From: Andreas Gruenbacher <a.gruenbacher@infosys.tuwien.ac.at>
- Date: Thu, 13 May 1999 16:40:22 +0200
- Organization: Technical University of Vienna
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
attached.
To compile:
> g++ -lpthread -o sockio sockio.cc
or
> g++ -lpthread -DIOSTREAM_GET_FIX -o sockio sockio.cc
========================== sockio.cc ==========================
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream.h>
#define xIOSTREAM_GET_FIXx
#ifdef IOSTREAM_GET_FIX
istream& istream::get(char& c)
{
if (ipfx1()) {
int ch = _strbuf->sbumpc();
if (ch == EOF) {
set(ios::eofbit|ios::failbit);
_gcount = 0;
}
else {
c = (char)ch;
_gcount = 1;
}
}
else
_gcount = 0;
isfx(); // <== this line added
return *this;
}
#endif
// --- 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,
sizeof(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
a.gruenbacher@infosys.tuwien.ac.at
Contact information: http://www.infosys.tuwien.ac.at/~agruenba