Структуры STL в статической памяти «теряют» данные в потоках - PullRequest
0 голосов
/ 02 марта 2010

Я пишу многопоточную демонстрационную программу с использованием pthreads, где один поток загружает данные в очередь STL, а другой поток читает из нее. Звучит банально, правда? К сожалению, данные, помещенные в очередь, исчезают. Я не новичок в многопоточности, и я не знаком со структурами памяти - однако, это поставило меня в тупик.

Это мои объявления для самой очереди и мьютекса, который ее защищает, которые находятся в заголовке, включенном в код клиента:

static std::queue<int32_t> messageQueue;
static pthread_mutex_t messageQueueLock; 

Когда программа запускается, она инициализирует мьютекс с общим атрибутом процесса:

pthread_mutexattr_t sharedAttr;
pthread_mutexattr_init(&sharedAttr);
pthread_mutexattr_setpshared(&sharedAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&messageQueueLock, &sharedAttr);

Затем он запускает потоки «производитель» и «потребитель» и позволяет им делать свое дело. Поток производителя помещает новый элемент в очередь и затем переходит в спящий режим. Вот строки, где он добавляет что-то в очередь:

pthread_mutex_lock(&messageQueueLock);
messageQueue.push(message);
pthread_mutex_unlock(&messageQueueLock);

Затем он спит и позволяет потребителю вступить во владение. Однако, когда поток потребителя проверяет элементы в очереди, очередь волшебным образом пуста.

Я прошел программу, используя gdb. Ниже приведен результат моего бега. Вы можете видеть, где производитель добавляет что-то в очередь, я печатаю размер очереди, чтобы убедиться, что она есть, происходит переключение контекста на поток потребителя, я снова печатаю размер очереди, и он пуст. Проверьте это:

(gdb) b main_ex.cpp:70
Breakpoint 1 at 0x100006a24: file main_ex.cpp, line 70.
(gdb) run
Starting program: a.out 
Reading symbols for shared libraries ++. done
Creating the mutex.
Producer thread starting up. 
PRODUCER: Creating a message to send.
PRODUCER: Adding the message to the queue.
[Switching to process 7432]

Breakpoint 1, yourProcess () at main_ex.cpp:70
70      pthread_mutex_lock(&messageQueueLock);
(gdb) n
71      messageQueue.push(message);
(gdb) p messageQueue.size()
$1 = 0
(gdb) n
72      pthread_mutex_unlock(&messageQueueLock);
(gdb) p messageQueue.size()
$2 = 1
(gdb) b consumer.cpp:81
Breakpoint 2 at 0x1000043f7: file consumer.cpp, line 81.
(gdb) c
Continuing.
PRODUCER: Sleep time!
[Switching to process 7432]

Breakpoint 2, Producer::processMessageQueue (this=0x1001000c0) at producer.cpp:81
81      pthread_mutex_lock(&messageQueueLock);
(gdb) n
83      if(messageQueue.empty()) {
(gdb) p messageQueue.size()
$3 = 0
(gdb) quit

Итак, я действительно не уверен, что происходит. Доступ к очереди возможен только в критической секции (как для чтения, так и для записи), очередь является статической, а заголовок if-def не должен включать несколько элементов.

Я благодарен за любую помощь, которую может предложить каждый!

Ответы [ 2 ]

5 голосов
/ 02 марта 2010

Защита заголовка защищает от многократного включения за единицу перевода . Тем не менее, различные единицы перевода будут повторно включать их.

В вашем случае кажется, что каждый из них получает свою собственную статическую очередь и мьютекс. Кроме того, подумайте, даже если бы вы были правы: без повторного включения заголовка модуль перевода не знал бы, что такое очередь и мьютекс! Вы пытаетесь использовать какой-то необъявленный идентификатор.

Вам нужен extern, который на самом деле противоположен статическому:

extern std::queue<int32_t> messageQueue;
extern pthread_mutex_t messageQueueLock;

Тогда в одной единице фактически определите их:

std::queue<int32_t> messageQueue;
pthread_mutex_t messageQueueLock;
1 голос
/ 02 марта 2010

Вы должны проверить, действительно ли два потока обращаются к одной и той же очереди или нет, если нет, попытайтесь избежать статической очереди и создать ее, например, в основной функции или в другом удобном месте.

...