Rather than a queue of fixed-size message objects, it might be possible to have a single circular buffer packed with variable-sized messages - i.e. something along the lines of
const int buffer_size = 1024*1024;char buffer[buffer_size];int buffer_read_pos = 0;int buffer_write_pos = 0;void AppendToBuffer(char* data, int size){ for (int i = 0; i < size; ++i) { buffer[buffer_write_pos] = data; buffer_write_pos = (buffer_write_pos + 1) % buffer_size; }}void Logger::Log(char* message){ Time time = ...; AppendToBuffer(&time, sizeof(time)); int len = strlen(message); AppendToBuffer(&len, sizeof(len)); AppendToBuffer(message, len);}...void ReadFromBuffer(char* data, int size){ for (int i = 0; i < size; ++i) { block while buffer_write_pos == buffer_read_pos; data = buffer[buffer_read_pos]; buffer_read_pos = (buffer_read_pos + 1) % buffer_size; }}void PrintLog(){ while (true) { Time time; int len; ReadFromBuffer(&time, sizeof(time)); ReadFromBuffer(&len, sizeof(len)); char* message = new char[len+1]; ReadFromBuffer(message, len); message[len] = '\0'; printf("%s", message); delete[] message; }}
(plus any necessary synchronisation (particularly if the compiler tries to optimise too much), minus any bugs). The adding-to-buffer thread doesn't have to do any slow memory allocation (which AddToQueue would presumably involve), and the messages don't have to be split into arbitrary fragments. It breaks if the adding-to-buffer thread gets more than buffer_size bytes ahead of the reading-from-buffer thread, but hopefully you can spare the memory for a bigger buffer (or make AppendToBuffer block if it's about to overflow, and wait for the log-printer thread to catch up). (Actually, I don't think that'd be more wasteful of memory than any other system, since the queued not-yet-processed messages have to be stored somewhere in any case - the only difference is that the fixed-size buffer will be that size for the lifetime of the program, which may or may not be worse than a variable-sized queue which will eventually grow to that size. And the maximum size will actually be slightly less than other systems, because there's no wasted space for padding lots of small buffers or managing dynamically-allocated queues.)