Nein, die Zuordnung ist nicht absolut threadsicher.
Ich schrieb ein Testprogramm, das zwei Threads erstellt. Beide enthalten ein shared_ptr zu einem Objekt, das eine cv :: Mat enthält. Ein Thread weist cv :: Mat einem zufällig erzeugten Bild zu, während der andere Thread eine lokale Kopie des cv :: Mat erstellt.
Dies stürzt sofort mit einem Doppel-frei. Wenn der Schreib-Thread den vorherigen überschreibt, während der Kopier-Thread zu kopieren beginnt, kopiert er einen cv :: Mat, dessen interne Daten ptr gerade gelöscht wurde. Wenn die lokale Kopie des Kopier-Threads den Gültigkeitsbereich verlässt, wird versucht, sie wieder freizugeben.
volatile bool g_done = false;
struct Object
{
cv::Mat cvMask;
};
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void thread1(boost::shared_ptr<Object> sharedObj)
{
while(!g_done)
{
sharedObj->cvMask = cv::Mat::ones(1 + (rand()% 1024), 1+(rand()%768), CV_8UC1);
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void thread2(boost::shared_ptr<Object> sharedObj)
{
while(!g_done)
{
cv::Mat localCopy = sharedObj->cvMask;
}
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void sigHandler(int signum)
{
fprintf(stderr, "Quitting...\n");
g_done = true;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
signal(SIGINT, sigHandler);
boost::shared_ptr<Object> sharedObj(new Object);
sharedObj->cvMask = cv::Mat::ones(1024,768, CV_8UC1);
boost::thread* t1 = new boost::thread(boost::bind(&thread1, _1), sharedObj);
boost::thread* t2 = new boost::thread(boost::bind(&thread2, _1), sharedObj);
while(!g_done)
{
usleep(1e6);
}
t1->join();
t2->join();
delete t1;
delete t2;
return 0;
}
Das scheint nicht atomar zu sein. Das 'if' könnte true zurückgeben, ein Kontextwechsel könnte passieren, ein Release und eine Zerstörung könnten eintreten, und dann würde der Kontext zurückschalten und CV_XADD würde segfault werden, außer wenn ich etwas verpasse. – Catskul
CV_XADD ist ein atomarer Test-and-Set (so testet es vor dem Hinzufügen auf refcount). der erste Teil (wenn Refcount) ist für einen schnellen Test vor dem Eintritt in atomare Op-Zustand. – Sam
Außerdem wird dieser Code, wie ich weiß, von den Jungs bei Google veröffentlicht.Ich glaube nicht, dass sie einen solchen Fehler machen würden. – Sam