I'm working on a project that utilizes producers and consumers for an operating systems class. Each producer and each consumer will be its own thread. The producers will generate records that will be stored in a global buffer, in which the consumer will then access to use the data. I am having a hard time figuring out how to use actual pthreads. My original plan was to create a Producer class and a Consumer class and simulate the threads, but we are told now not to do so. Is there a c++ class for this? Also, for the buffer, I was initially creating an array of structs (the struct being the record created by the producer), but was now told I need to actually use Buffer. Are there any basic tutorials for this out there, or can someone shed some light on this topic on a good place to start.

Any help is appreciated :)


Miss VaVaZoom

Recommended Answers

All 10 Replies

If you are not obliged to use pthreads, I would highly recommend using Boost.Thread instead. Both because it is so easy and it is about to be the standard multi-threading library for C++0x.

As for your problem, it is quite a classic and important scenario in multi-threaded applications. The term Buffer is just a general term for chunk of memory in which you temporarily store elements to be processed (unless your prof meant something very specific that I am not aware of). It can be implemented in whichever way you like, but essentially, it is a queue (FIFO) (so you would probably want to use the STL container of the same name).

As for implementing it, it will most likely involve protecting the buffer with a mutex (available in Boost.Thread or in pthread) and have the producer add elements to the end of the queue and have the consumer take elements from the start of the queue if it is not empty. Now, the queue becomes a buffer between the producer and consumer because if either one slows down momentarily for one reason or another, it won't affect the performance of the other. The mutex is critical here because you cannot have both sides tampering with the same memory at the same time, so their operations on the buffer have to be mutually exclusive (i.e. mutex). However, there is a way to avoid using a mutex, but that is for you to figure out.

Thanks, that was really helpful. We do have to use pthreads, so I am looking into coding this in C instead of C++. I don't have any experience in C, but I'm assuming it's not terribly difficult to transition. One question about the buffer...After reading what you had to say, would it be smart then to use a queue and keep record of how many items are being placed in it up until a certain point, rather than an array of a particular size?

Well I certainly would not recommend you do it in C if you already used to C++ (that would be a regression, C is only more restrictive).

About the buffer, if you use the queue class than this is a non-issue because this class will keep track of the number of items on the queue.

If you want or need to implement your own queue, then there are a few basic rules.
1. Make the start and end positions available (i.e. you know where the first and last elements are located in memory).
2. Make adding an element at the end and subtracting an element from the start as simple as possible (without needing to reallocate new memory and copy blocks of memory around).
3. Avoid reallocating memory.
So, a typical C-style queue implementation would use a large array (either a fixed size or a dynamic size). Then, you keep two pointers or two indexes, one for the start position and one for the end position. Adding an element to the end is just a matter of setting to element pointed-to by the end-pointer to the new element value, and then incrementing it (while making it wrap around back to index 0 if it reaches the end of the array). Subtract an element from the start is just a matter of incrementing the start pointer. If, at any point, the end pointer reaches the start pointer as it gets incremented, your buffer is full and you should either resize if it is a dynamic array, or stop with some error report like "buffer overflow". If the start pointer reaches the end pointer, the queue is empty (and your consumer has to wait for a new element to come). This type of buffer implementation is classic and people often use those types of "rolling arrays" (i.e. rapidly changing data set rolls around a larger but fixed array).

An implementation like that can be a bit overly expensive in memory. If your individual elements are large in size, it might be a good idea to use a linked-list to store the elements instead.

@David: Yeah these are perfectly good examples. I just added a printout in the loop and removed the divide-by-zero situation by removing the zeroth iteration.

Thanks for the tips...I believe I am able to use the Queue class, however knowing how to implement my own is ideal.

Regarding the C or C++ issue. I'd like to keep it in C++, but if pthread.h is written in C, am I still able to compile in C++?

>>Regarding the C or C++ issue. I'd like to keep it in C++, but if pthread.h is written in C, am I still able to compile in C++?

Absolutely. C is essentially a subset of C++. Putting a few issues aside, most C code can be directly compiled with a C++ compiler. As for libraries like pthread, they are "C-style" libraries which means they compile for either C or C++ without any trouble (and in fact, when you include pthread.h you are technically only including the header to an already compiled library, so even if pthread was written in some obscure programming language, it wouldn't make a difference because you don't need to really compile anything of it, you just use it). That was also the motivation behind enforcing backward compatibility of C++ to C such that all those kinds of libraries wouldn't have to be rewritten for C++.

I am able to start a new thread for this question, however it pertains to the producer consumer problem I am working on, and am hoping you can still help.

I've finally gotten this to compile, however when I run it, I get the message:
Segmentation fault (core dumped)

I realize this has to do with memory. Is there a way to test where the problem is?

Quoting wikipedia: "Generally, segmentation faults occur because of an attempt to dereference a pointer that is either NULL, points to random memory (probably never initialized to anything), or points to memory that has been freed/deallocated/"deleted"."
That's what you should be looking for. Basically, anywhere you use memory pointed-to by a pointer, which includes accessing an array or vector by the index. You will get a segfault if you access elements beyond the array or vector size or if you dereference a pointer that is no longer or never was valid. If you have implemented this provider-consumer scheme and have not protected your memory with a mutex, that could very well explain it (especially if the problem seems to occur randomly (random times, random runs)).

To find the error, beyond just outputting log-messages every two lines of code (which you mind as well do if your code is below a few thousand lines of code), you need to use either a debugger or a memory profiler. On your Unix-like system, there are basically two essential tools: gdb and valgrind. GDB will let you put breakpoints into the code, step through it and inspect the variable values (i.e. a debugger), so if you have suspicions about where the error occurs or what variables might be corrupt it helps a lot and is usually all you need. Valgrind is a memory profiling tool, essentially, it sets up a virtual machine on which to run the program which allows it to keep track of all dynamic memory allocations and more. With valgrind you will get the segfault reported with the name of the variable (pointer) that caused it and a complete back-trace (i.e. the sequence of function calls traced back from where the error occurred to the main() function). Both are free and installable through your favorite package management system of course.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, learning, and sharing knowledge.