The following attached (downsized) program implements a queue which
contains a single worker process. Int's that are pushed into the queue
are popped by
the worker and processed... The problem is, the program ends up with an
segmentation fault. Valgrind tells me that the stack is overwritten.
==4927== Conditional jump or move depends on uninitialised value(s)
==4927== at 0x8073536: strstr (in
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x80609F5: pthread_initialize (smp.h:47)
==4927== by 0x80B2DE1: (within
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x80480E8: (within
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x80641A0: __libc_csu_init (in
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x8063FC2: __libc_start_main (in
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x8048120: ??? (start.S:102)
==4927==
==4927== Syscall param write(buf) points to uninitialised byte(s)
==4927== at 0x8063044: write (in
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x804C241: boost::thread::thread(boost::function0boost::function_base > const&) (in
/local/home/lkunert/projects/pg-build-4.0.3/src/cdag/threads/queue_error)
==4927== by 0x804AD26: QueueError::QueueError(unsigned)
(QueueError.cxx:74)
==4927== by 0x8048287: main (QueueError.cxx:150)
==4927== Address 0x52BFE04C is on thread 1's stack
Line 74 corresponds to the initailisation of the worker. The
thread-manual writes:
*explicit* thread(*const* boost::function0<*void*>& threadfunc);
*Effects*: Starts a new thread of execution and constructs a thread
http://www.boost.org/doc/html/thread.html object representing it.
Copies |threadfunc| (which in turn copies the function object wrapped by
|threadfunc|) to an internal location which persists for the lifetime of
the new thread of execution. Calls |operator()| on the copy of the
|threadfunc| function object in the new thread of execution.
Which sound good to me. Were is the mistake.
class QueueError
{
// *** Typedefs
*************************************************************
private:
typedef std::queue<int> Queue;
typedef boost::thread Thread;
public:
typedef Queue::size_type ST;
// *** Inner Classes
********************************************************
private:
class Worker
{
private:
QueueError* outer_p_;
public:
Worker( QueueError* outer_p )
: outer_p_( outer_p )
{};
public:
void
operator()()
{
outer_p_->worker_run_();
};
};
// *** Attributes
************************************************************
public:
private:
ST max_queue_size_;
Queue queue_;
Thread thread_;
boost::mutex monitor_;
boost::condition space_available_, job_available_;
// *** Constructors / Destructors
********************************************
public:
explicit
QueueError( ST max_queue_size =1000 )
: max_queue_size_( max_queue_size )
, thread_( Worker( this ))
{};
// *** Methods
***************************************************************
public:
void
push( int i )
{
boost::mutex::scoped_lock lock( monitor_ );
while( queue_.size() >= max_queue_size_ )
{
space_available_.wait( lock );
};
queue_.push( i );
job_available_.notify_one();
};
protected:
void
worker_run_()
{
int i =0;
while( true )
{
i = worker_pop_();
worker_work_( i );
};
};
int
worker_pop_()
{
boost::mutex::scoped_lock lock( monitor_ );
while( queue_.empty())
{
job_available_.wait( lock );
};
int i = queue_.front();
queue_.pop();
space_available_.notify_one();
return i;
};
void
worker_work_( int i )
{
for( int ii= 0; ii < i; ++ii )
{
// do some work
double divident = 10000;
double sum;
for( uint divisor =1; divisor < divident; ++divisor )
{
sum = divident / divisor;
};
};
};
}; // class QueueError
int main()
{
QueueError q;
q.push( 10 );
q.push( 9 );
q.push( 8 );
q.push( 7 );
q.push( 6 );
return 0;
};