Trådsäkerhetsfråga: process<->process Shared memory(windows)
Då var man där igen :P. Håller på att koda ett dataextraheringsprogram till en trevlig flygsimulator som heter BMS (http://www.youtube.com/watch?v=RwZFjKOdWOI&feature=related). BMS exporterar data genom windows shared-memory-API (se http://msdn.microsoft.com/en-us/library/aa366551(v=vs.85).asp...).
Jag har redan skrivit testkod för att läsa detta minne från min egen process, men, har kört fast på en punkt. BMS tillhandahåller inte några synkroniseringsprimitiver typ mutexes eller semaphorer. Jag har inget krav som säger att minnet jag läser konsekvent måste vara från en simulatoriteration, det gör inte om det blir lite korruption var 10.000:e frame :).
exempelkod som fungerar:
#include <iostream>
#include <windows.h>
#include "Flight Data.h"
using namespace std;
int main() {
const HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, "FalconSharedOsbMemoryArea");
if (hMapFile != NULL) {
const OSBData * data = (OSBData *) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, sizeof(OSBData));
if (data != NULL) {
while (true) {
cout << endl << data->leftMFD[2].line1;
Sleep(1000);
}
UnmapViewOfFile(data);
} else {
cout << "Could not map view of file";
}
CloseHandle(hMapFile);
} else {
cout << "Could not open file mapping object";
}
return 0;
}
MEN:
1. Jag vill inte att kompilatorn bestämmer sig för att optimera bort mina läsningar (tänker på while(myVal) när myVal sätts till false av en annan tråd t.ex kan kompilatorn bestämma sig för att det alltid är true eftersom den lokala tråden aldrig ändrar det.)
2. Jag vill inte att datorn bestämmer sig för att efter läsning #1 av minnet , "aha, nu har vi läst det till vår cache en gång, och därför behöver vi aldrig hämta datan från RAMet igen.)
Det kan vara värt att nämna att detta körs helt i windows, jag kompilerar & länkar mitt C/C++program med MingW genom eclipse, och det är inte tänkt att köras på några andra plattformar än x86 (dock kan det vara aktuellt att även kompilera en 64bitars-version).
Jag har försökt läsa på lite om minnesbarriärer, men kan inte komma fram till något konsekvent. Vad jag förstått så kan man tex. lägga in assembly-inlines i sin kod som "__asm__ __volatile__ ("" ::: "memory");" för att skapa en barriär. Om jag har förstått det rätt så ska barriären garantera att saker inte ordnas om, men jag hittar ingenting om att barriären skulle tvinga en läsning från faktiskt ram. (BMS garanterar förresten att datan skrivs till ram och inte cachas på dess sida )
Ok, hoppas någon förstod det här, alla tips välkomna :). Hade det varit min egen kod på "båda sidor" skulle det ju vara lätt (slänga in ett mutex, vips, löst), men nu har jag ju bara en minnesadress som pekar på ett block vars innehåll ändras av någon annan process vid godtyckliga tidpunkter, och det enda jag vill garantera är att när jag kallar på "readDataFromBlocK" eller vad man nu ska kalla den funktionen som jag kommer skriva, så skall det läsas strikt direkt ur den faktiska adressen och inte ur någon *** cache :).
Det jag gör just nu är att lägga till volatile framför min data-variabel: volatile const OSBData * data, men det känns ju fel på något sätt...främst för att allt man läser om volatile verkar som det inte stämmer :).
Vad ska jag stoppa in i min while-loop i koden ovan för att tvinga en läsning från faktiskt ram, någon som vet?
Every time you create an iterator: God kills a kitten.