Como posso sincronizar três threads?
Meu aplicativo consiste no processo principal e em dois threads, todos em execução simultaneamente e utilizando três filas de quinze:
O fifo-q é Qmain, Q1 e Q2. Internamente, as filas usam um contador que é incrementado quando um item é colocado na fila e decrementado quando um item é 'obtido' da fila.
O processamento envolve dois threads,
QMaster, que sai do primeiro e segundo trimestres e é colocado no Qmain,
Monitor, colocado no Q2,
e o processo principal, que sai do Qmain e entra no primeiro trimestre.
O loop QMaster-thread verifica consecutivamente as contagens de Q1 e Q2 e, se houver algum item no q, ele recebe e coloca no Qmain.
O loop Monitor-thread obtém dados de fontes externas, empacota e coloca no Q2.
O processo principal do aplicativo também executa um loop verificando a contagem de Qmain e, se houver algum item, obtém um item do Qmain a cada iteração do loop e o processa ainda mais. Durante esse processamento, ele ocasionalmente coloca um item no primeiro trimestre para ser processado posteriormente (quando é obtido do Qmain por sua vez).
O problema:
Eu implementei tudo como descrito acima, e funciona por um tempo aleatório (curto) e depois trava. Eu consegui identificar a origem da falha no incremento / decremento da contagem de um fifo-q (isso pode acontecer em qualquer uma delas).
O que eu tentei:
Usando três mutexs: QMAIN_LOCK, Q1_LOCK e Q2_LOCK, que eu tranco sempre que qualquer operação de get / put é feita em um fifo-q relevante. Resultado: o aplicativo não funciona, apenas trava.
O processo principal deve continuar em execução o tempo todo, não deve ser bloqueado em uma 'leitura' (pipes nomeados falham, socketpair falha).
Algum conselho?
Eu acho que não estou implementando o mutex corretamente, como isso deve ser feito?
(Quaisquer comentários sobre como melhorar o design acima também são bem-vindos)
[edit] abaixo estão os processos e o fifo-q-template:
Onde e como devo colocar o mutex para evitar os problemas descritos acima?
main-process:
...
start thread QMaster
start thread Monitor
...
while (!quit)
{
...
if (Qmain.count() > 0)
{
X = Qmain.get();
process(X)
delete X;
}
...
//at some random time:
Q2.put(Y);
...
}
Monitor:
{
while (1)
{
//obtain & package data
Q2.put(data)
}
}
QMaster:
{
while(1)
{
if (Q1.count() > 0)
Qmain.put(Q1.get());
if (Q2.count() > 0)
Qmain.put(Q2.get());
}
}
fifo_q:
template < class X* > class fifo_q
{
struct item
{
X* data;
item *next;
item() { data=NULL; next=NULL; }
}
item *head, *tail;
int count;
public:
fifo_q() { head=tail=NULL; count=0; }
~fifo_q() { clear(); /*deletes all items*/ }
void put(X x) { item i=new item(); (... adds to tail...); count++; }
X* get() { X *d = h.data; (...deletes head ...); count--; return d; }
clear() {...}
};