Я разработал класс очереди блокировки следующим образом
class Blocking_queue
{
public:
Blocking_queue();
int put(void* elem, size_t elem_size);
int take(void* event);
unsigned int get_size();
private:
typedef struct element
{
void* elem;
size_t elem_size;
struct element* next;
}element_t;
std::mutex m_lock;
std::condition_variable m_condition;
unsigned int m_size;
element_t* m_head;
element_t* m_tail;
};
Я хочу, чтобы класс был как можно более универсальным, поэтому я использую указатель void, который выделяется при добавлении элемента в очередь и освобождается при удалении из него.
int Blocking_queue::take(void* event)
{
element_t* new_head = NULL;
int ret = 0;
// Queue empty
if(nullptr == m_head)
{
// Wait for an element to be added to the queue
std::unique_lock<std::mutex> unique_lock(m_lock);
m_condition.wait(unique_lock);
}
if(nullptr == realloc(event, m_head->elem_size))
{
ret = -1;
}
else
{
// Take element from queue
memcpy(event, m_head->elem, m_head->elem_size);
ret = m_head->elem_size;
new_head = m_head->next;
free(m_head->elem);
free(m_head);
m_head = new_head;
if(nullptr == m_head)
{
m_tail = nullptr;
}
m_size -= 1;
}
return ret;
}
Если очередь пуста, функция take()
ожидает m_condition
, пока не будет добавлен новый элемент.
Необходимо указатель event
для копирования содержимого элемента перед его освобождением.
Чтобы быть уверенным, что данный указатель имеет правильный размер для копирования содержимого элемента, я перераспределяю указатель с его размером.
Проблема, с которой я столкнулся, заключается в том, что она не позволяет передавать переменную локали функции, потому что она расположена в стеке.
Так что, если я сделаю что-то подобное
void function()
{
unsigned int event = 0;
queue->take(&event);
}
У меня будет ошибка invalid old size
на realloc.
Так что, если я передам нулевой указатель или переменную, выделенную из кучи, это будет работать, но если я передам адрес переменной стека, это не будет.
Есть ли способ разрешить передачу адреса переменной стека в функцию take()
?