Inleiding
Na lang zelf geprobeerd te hebben een oplossing te vinden voor onderstaande probleem heb ik toch besloten om jullie om raad te vragen.

De belangrijkste taken van mijn programma zijn het ontvangen en verzenden van data.
- Het doel van de ontvanger is het verwerken van interrupts tot betekenisvolle data. Het doel van de zender is het verzenden van die data. Voor het op te lossen probleem maakt het niet uit of dit nu het verzenden en ontvangen van IR data is of 433.92Mhz enz.
- Het doel van de broadcaster is om alle acties die er in het programma gebeuren (via een API) te delen met externe programma's.
- Aanvullend biedt mijn programma ook de mogelijkheid van eventing en biedt het een ingebouwde webGUI aan.
Om alles zonder al te veel vertraging te laten lopen werkt het geheel van een aantal threadsafe queues. Dat betekent dat de ontvanger, zender en broadcaster logica telkens uit twee functie bestaan (zie verderop). In het geval van de ontvanger is er één functie die de ontvanger lijst vult en één functie die de ontvanger lijst uitleest. Dit heb ik toen zo geïmplementeerd zodat ik er zeker van kon zijn dat ik geen belangrijke informatie mis aan de ontvangst kant mocht de broadcaster te lang bezig zijn met zijn taak. Uiteindelijk heb ik die logica doorgetrokken in alle functionaliteit die in dit schema te zien is.
Om het probleem goed te doorgronden is het dus goed om te weten dat mijn programma nu gebruik maakt van de volgende threads:
- receive_queue / receive_process
- send_queue / send_process
- broadcast_queue / broadcast_process
- events_queue / events_process
- webserver_queue / webserver_process
Zoals gebruikelijk word de consistentie van de queue's bewaakt door locks:
Probleem
Zoals ik in de titel aangeef ontstaat hier het risico van een deadlock. Een gangbare flow van het programma is als volgt.
Er wordt een bepaalde code ontvangen, die wordt door de broadcaster doorgestuurd naar de eventing functionaliteit. De gebruiker heeft bepaald dat er aan de hand van deze code een andere code moet worden verzonden. De zender functie verteld vervolgens weer aan de broadcaster dat er iets verzonden is zodat er daaropvolgende weer een event kan plaatsvinden en ook de GUIs de kans krijgen om de verandering te visualiseren.
Zoals te zien is ontstaat het probleem op het moment dat de eerste broadcast functie nog bezig is op het moment dat hij weer opnieuw aangeroepen wordt. De oude lock is nog niet vrijgegeven terwijl er nieuwe wordt aangevraagd.
In de basis van zenden / ontvangen en broadcasten werkte alles prima. Nu echter deze problemen zich voordoen kom ik tot de conclusie dat deze implementatie zo niet houdbaar is voor de huidige complexiteit.
Tussenoplossing
Om het geheel toch werkend te krijgen is alle functionaliteit die afhankelijk is van de broadcaster nu via een socket verbinding aan het geheel geknoopt. Hierdoor draaien de GUIs en de eventing functionaliteit eigenlijk als aparte programma's naast het hoofdprogramma.
Zelf bedacht alternatief
Andere ideeën die ik had was het creëren van een soort event-driven-functionaliteit / observer pattern. De receiver laat weten dat er een code is ontvangen, deze triggered een functie die nagaat welke geregistreerde functies er geïnteresseerd zijn in deze informatie en voert deze functies uit.
Het probleem hiervan is dat dit (naar mijn idee) alleen werkt wanneer deze functies ook weer threaded worden gestart, omdat je anders opnieuw het risico loopt dat een trage GUI de receiver kan blokkeren. Elke thread krijgt dan een kopie van de data zodat je ook niet aan een threadsafe queue vast zit. Zou ik per event een nieuwe thread moeten starten, dan worden er in het ergste geval een tientallen keren per seconde threads gestart en weer gestopt. Dat is dus ook niet ideaal, maar zou in theorie wel alternatief kunnen zijn voor mijn probleem.
Andere oplossingen?
En op dat punt kwam ik er niet meer uit en besloot ik maar weer eens zelf een vraag te stellen
Na lang zelf geprobeerd te hebben een oplossing te vinden voor onderstaande probleem heb ik toch besloten om jullie om raad te vragen.

De belangrijkste taken van mijn programma zijn het ontvangen en verzenden van data.
- Het doel van de ontvanger is het verwerken van interrupts tot betekenisvolle data. Het doel van de zender is het verzenden van die data. Voor het op te lossen probleem maakt het niet uit of dit nu het verzenden en ontvangen van IR data is of 433.92Mhz enz.
- Het doel van de broadcaster is om alle acties die er in het programma gebeuren (via een API) te delen met externe programma's.
- Aanvullend biedt mijn programma ook de mogelijkheid van eventing en biedt het een ingebouwde webGUI aan.
Om alles zonder al te veel vertraging te laten lopen werkt het geheel van een aantal threadsafe queues. Dat betekent dat de ontvanger, zender en broadcaster logica telkens uit twee functie bestaan (zie verderop). In het geval van de ontvanger is er één functie die de ontvanger lijst vult en één functie die de ontvanger lijst uitleest. Dit heb ik toen zo geïmplementeerd zodat ik er zeker van kon zijn dat ik geen belangrijke informatie mis aan de ontvangst kant mocht de broadcaster te lang bezig zijn met zijn taak. Uiteindelijk heb ik die logica doorgetrokken in alle functionaliteit die in dit schema te zien is.
Om het probleem goed te doorgronden is het dus goed om te weten dat mijn programma nu gebruik maakt van de volgende threads:
- receive_queue / receive_process
- send_queue / send_process
- broadcast_queue / broadcast_process
- events_queue / events_process
- webserver_queue / webserver_process
Zoals gebruikelijk word de consistentie van de queue's bewaakt door locks:
code:
1
2
3
4
| [lock] vul queue [unlock] [signal] |
Probleem
Zoals ik in de titel aangeef ontstaat hier het risico van een deadlock. Een gangbare flow van het programma is als volgt.
code:
1
| Receiver > Broadcast > Event > Sender > Broadcast |
Er wordt een bepaalde code ontvangen, die wordt door de broadcaster doorgestuurd naar de eventing functionaliteit. De gebruiker heeft bepaald dat er aan de hand van deze code een andere code moet worden verzonden. De zender functie verteld vervolgens weer aan de broadcaster dat er iets verzonden is zodat er daaropvolgende weer een event kan plaatsvinden en ook de GUIs de kans krijgen om de verandering te visualiseren.
Zoals te zien is ontstaat het probleem op het moment dat de eerste broadcast functie nog bezig is op het moment dat hij weer opnieuw aangeroepen wordt. De oude lock is nog niet vrijgegeven terwijl er nieuwe wordt aangevraagd.
In de basis van zenden / ontvangen en broadcasten werkte alles prima. Nu echter deze problemen zich voordoen kom ik tot de conclusie dat deze implementatie zo niet houdbaar is voor de huidige complexiteit.
Tussenoplossing
Om het geheel toch werkend te krijgen is alle functionaliteit die afhankelijk is van de broadcaster nu via een socket verbinding aan het geheel geknoopt. Hierdoor draaien de GUIs en de eventing functionaliteit eigenlijk als aparte programma's naast het hoofdprogramma.
Zelf bedacht alternatief
Andere ideeën die ik had was het creëren van een soort event-driven-functionaliteit / observer pattern. De receiver laat weten dat er een code is ontvangen, deze triggered een functie die nagaat welke geregistreerde functies er geïnteresseerd zijn in deze informatie en voert deze functies uit.
Het probleem hiervan is dat dit (naar mijn idee) alleen werkt wanneer deze functies ook weer threaded worden gestart, omdat je anders opnieuw het risico loopt dat een trage GUI de receiver kan blokkeren. Elke thread krijgt dan een kopie van de data zodat je ook niet aan een threadsafe queue vast zit. Zou ik per event een nieuwe thread moeten starten, dan worden er in het ergste geval een tientallen keren per seconde threads gestart en weer gestopt. Dat is dus ook niet ideaal, maar zou in theorie wel alternatief kunnen zijn voor mijn probleem.
Andere oplossingen?
En op dat punt kwam ik er niet meer uit en besloot ik maar weer eens zelf een vraag te stellen
Sinds de 2 dagen regel reageer ik hier niet meer