Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Mutex in ostream operator - doesn't work

54 views
Skip to first unread message

Hansel Stroem

unread,
Jan 28, 2008, 10:20:22 PM1/28/08
to
Good evening dear newsgroop,

I am trying to synchronize output to ostreams such as cout and cerr for
threaded logging purposes. And it doesn't seem to work. The blurb of code
below is supposed to do following :

ostream& operator <<(ostream& out, StreamLocker& SL)
{

if (not_locked)
{
pthread_mutex_lock(this_lock);
not_lock = false;
}
else // if locked
{
pthread_mutex_unlock(this_lock);
not_lock = true;
}

return out;
}

Rest of code is debugging messages and attempts to get it to work with
flush() et al. Nothing works; output is as mingled as it could be. Please
help me kindly.

Thank you,
Not A Coder.
-----------------------------------------------
#include <iostream>
#include <pthread.h>
#include <unistd.h>


using namespace std;

static pthread_mutex_t stderr_lock;
static pthread_mutex_t stdout_lock;

class StreamLocker
{
public:
bool locked;
pthread_mutex_t my_lock;
StreamLocker();
void InitLock(pthread_mutex_t mutex_lock);
friend ostream& operator<<(ostream& out, StreamLocker &sl);
};

static StreamLocker SL;

StreamLocker::StreamLocker()
{
cout << "Creating StreamLocker" << endl;
this->locked = false;
pthread_mutex_init(&my_lock, NULL);
pthread_mutex_init(&stderr_lock, NULL);
pthread_mutex_init(&stdout_lock, NULL);
cout << "Created StreamLocker" << endl;
}

ostream& operator <<(ostream& out, StreamLocker &sl)
{
if (!sl.locked)
{
if (out == cerr)
{
out << "LK ER";
pthread_mutex_lock(&stderr_lock);
}
else if (out == cout)
{
out.flush();
out << "*LK OU*";
if ( pthread_mutex_lock(&stdout_lock) != 0 )
perror("Couldn't obtain lock");
}
else
{
out << "LK SE";
pthread_mutex_lock( &(sl.my_lock) );
}
}
else
{
out.flush();
if (out == cerr)
{
out << "ULK ER";
pthread_mutex_unlock(&stderr_lock);
}
else if (out == cout)
{
out << "*ULK OU*";
if ( pthread_mutex_unlock(&stdout_lock) != 0 )
perror("Couldn't unlock");
}
else
{
out << "ULK SE";
pthread_mutex_unlock(& (sl.my_lock)) ;
}
}
sl.locked = !sl.locked;
// out.flush();
return out;
}

void StreamLocker::InitLock(pthread_mutex_t mutex_lock)
{
pthread_mutex_init(&mutex_lock, NULL);
}


typedef void* (*thread_body) (void*) ;

template<int N>
void* Thread_Body(void* arg)
{
unsigned long cycle = 1;
while ( ++cycle > 0)
{
cout << SL ;
cout << "Thread ## " << N << " in cycle ## " << cycle << " speaking with
id " << pthread_self() << endl ;
cout << SL;
if ( (random() % 111)==0 )
sleep( 1 );
}
}

int main(int argc, char** argv)
{
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_t thread_id;

thread_body tb_1 = Thread_Body<1>, tb_2 = Thread_Body<2> , tb_3 =
Thread_Body<3>;

pthread_create(&thread_id, &thread_attr, tb_1, NULL);
pthread_create(&thread_id, &thread_attr, tb_2, NULL);
pthread_create(&thread_id, &thread_attr, tb_1, NULL);
pthread_create(&thread_id, &thread_attr, tb_3, NULL);
pthread_create(&thread_id, &thread_attr, tb_2, NULL);
pthread_create(&thread_id, &thread_attr, Thread_Body<7>, NULL);

pthread_join(thread_id, NULL);
}

Ian Collins

unread,
Jan 29, 2008, 12:11:15 AM1/29/08
to
Hansel Stroem wrote:
> Good evening dear newsgroop,
>
> I am trying to synchronize output to ostreams such as cout and cerr for
> threaded logging purposes. And it doesn't seem to work. The blurb of code
> below is supposed to do following :
>
> ostream& operator <<(ostream& out, StreamLocker& SL)
> {
>
> if (not_locked)
> {
> pthread_mutex_lock(this_lock);
> not_lock = false;
> }
> else // if locked
> {
> pthread_mutex_unlock(this_lock);
> not_lock = true;
> }
>
> return out;
> }
>
I'm not sure what your are trying to do, but consider
pthread_mutex_trylock(), which removes the unguarded tests of
not_locke(d) (are there two variables, or a typo?).

--
Ian Collins.

Dmitriy Vyukov

unread,
Jan 29, 2008, 5:47:04 AM1/29/08
to
On Jan 29, 6:20 am, "Hansel Stroem" <han...@stroem.com> wrote:

> I am trying to synchronize output to ostreams such as cout and cerr for
> threaded logging purposes. And it doesn't seem to work. The blurb of code
> below is supposed to do following :


locked flag must be thread-local (one per thread), not global
Otherwise one thread locks mutex, and another see locked==true and
unlocks mutex


Dmitriy V'jukov

Torsten Robitzki

unread,
Jan 29, 2008, 6:59:18 AM1/29/08
to
Hansel Stroem wrote:

> Good evening dear newsgroop,
>
> I am trying to synchronize output to ostreams such as cout and cerr for
> threaded logging purposes. And it doesn't seem to work. The blurb of code
> below is supposed to do following :

The problem is that you want to do two different things with one
function. Why not using two different functions for locking and
unlocking? I think operator<< doesn't fit here because you really don't
want to output a mutex on a stream.

lock(std::cout, LS);
std::cout << "Hello " << "World" << std::endl;
unlock(std::cout, LS);

But as every stream output operator can throw an exception, using a
guard might by more convenience (the constructor calls lock() and the
destructor calls unlock():

stream_guard lock(std::cout, LS);
std::cout << "Hello " << "World" << std::endl;

And as one can attach additional data to a stream (ios_base::xalloc(),
ios_base::pword(), I would attach a mutex to a stream and this would
lead to:

stream_guard lock(std::cout);
std::cout << "Hello " << "World" << std::endl;

You have to make sure that no custom stream operators perform a locking
on a stream or you have to use recursive locks. Personally I would write
a thread save stream buffer and use a stream per thread, this would
solve the problem of a potential double lock too.

best regards,
Torsten

--
kostenlose Wirtschaftssimulation: http://www.financial-rumors.de

Chris Thomasson

unread,
Jan 29, 2008, 3:13:13 PM1/29/08
to
On Mon, 28 Jan 2008 22:20:22 -0500, Hansel Stroem wrote:

> Good evening dear newsgroop,
>
> I am trying to synchronize output to ostreams such as cout and cerr for
> threaded logging purposes. And it doesn't seem to work. The blurb of
> code below is supposed to do following :

[...]

There is a way to get fairly scalable logging scheme. You create a single
logger thread which maintains a list of application threads that can
generate logging information. If a one of those threads wants to post
something to the log it simply grabs a log buffer from its local pool
(e.g. TLS); fills it with data (e.g., time-stamp, priority, log message,
output, ect...); en-queues it onto its local log queue; signals the
logging thread which in turn flushes the local queues of each of its
registered threads and begins to process the log requests (e.g., write to
file).

You can get total order by incrementing a global version counter and
storing the result in the time-stamp somewhere. That way the logger thread
can sort by the version number stored in the timestamps _and_ priority
before it writes anything to the output in a log entry.

The logging thread can wake-up and process everything one every N seconds
or so. That way, you can omit the signaling except for the most time
urgent messages.

POSIX works well with this scheme. Also, you can use POSIX and a high-
performance single-producer/consumer lock-free queues in this scheme to
make virtually zero-overhead logging library.

0 new messages