daviddoria
Posting Virtuoso
1,996 posts since Feb 2008
Reputation Points: 437
Solved Threads: 204
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.
mike_2000_17
Posting Virtuoso
2,134 posts since Jul 2010
Reputation Points: 1,634
Solved Threads: 457
daviddoria
Posting Virtuoso
1,996 posts since Feb 2008
Reputation Points: 437
Solved Threads: 204
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.
mike_2000_17
Posting Virtuoso
2,134 posts since Jul 2010
Reputation Points: 1,634
Solved Threads: 457
@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.
mike_2000_17
Posting Virtuoso
2,134 posts since Jul 2010
Reputation Points: 1,634
Solved Threads: 457
>>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++.
mike_2000_17
Posting Virtuoso
2,134 posts since Jul 2010
Reputation Points: 1,634
Solved Threads: 457
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.
mike_2000_17
Posting Virtuoso
2,134 posts since Jul 2010
Reputation Points: 1,634
Solved Threads: 457