I am writing a simple multi-threaded buffer. It’s purpose is to hold data from the sound card until I can process them. It is implemented as a simple linked list (Element = list element, DataQueue = actual buffer, DataChunk = object with data):
class Element{
private:
Element *next;
DataChunk *data;
public:
Element(DataChunk *data);
~Element();
DataChunk *getData();
Element *nextElement();
void setNextElement(Element *nextElement);
};
class DataQueue{
private:
int size;
Element *top;
Element *last;
HANDLE lock;
public:
DataQueue();
void append(DataChunk *chunk);
Element *cut(int *cutSize);
};
Element::Element(DataChunk *data){
this->data = data;
this->next = NULL;
}
Element::~Element(){
delete data;
}
DataChunk *Element::getData(){
return data;
}
Element *Element::nextElement(){
return next;
}
void Element::setNextElement(Element *nextElement){
this->next = nextElement;
}
DataQueue::DataQueue(){
size = 0;
top = NULL;
last = NULL;
lock = CreateEvent(NULL, TRUE, FALSE, TEXT("Lock"));
if(lock == NULL){
printf("Error code: %ld\n", GetLastError());
exit(EXIT_FAILURE);
}
}
void DataQueue::append(DataChunk *chunk){
WaitForSingleObject(lock, INFINITE);
SetEvent(lock);
Element *element = new Element(chunk);
if(top == NULL){
top = element;
}
else{
last->setNextElement(element);
}
last = element;
ResetEvent(lock);
}
Element *DataQueue::cut(int *cutSize){
WaitForSingleObject(lock, INFINITE);
SetEvent(lock);
Element *toReturn = top;
*cutSize = size;
top = NULL;
last = NULL;
size = 0;
ResetEvent(lock);
return toReturn;
}
The usage pattern is like this:
The audio driver (ASIO) is using callback functions to notify me when its buffers are ready for processing. This happens A LOT (dozen times per second). But I need to process the data only once per 5 seconds or so. So I use my own buffer to store 5 secs worth of sound data. Driver creates its own thread and executes the callback function. From this thread, I call append() and append the data from device buffers to my buffer. When the actual processing thread comes along, it cuts the buffer by getting the first element and reseting the buffer to 0 elements.
The problem is thread synchronization. The cut() and access() functions are mutually exclusive. I have Event HANDLE and I wait on this Event. I have some experience with Java, and am totally new to these Win32 APIs. Am I doing it right? Just like this, the program crashes on WaitForSingleObject, probably because I don’t have SYNCHRONIZATION access right (c0000005). How can I set it to a thread created by a driver? Will this work even when there are multiple processing threads?
EnterCriticalSection did the trick.