Kürzlich stellte ich eine Frage mit dem Titel "Ist Malloc-Thread sicher?" und darin fragte ich: "Ist Malloc wieder am Start?"
Ich hatte den Eindruck, dass alle Wiedereinsteiger threadsicher sind.
Ist diese Annahme falsch?
quelle
Kürzlich stellte ich eine Frage mit dem Titel "Ist Malloc-Thread sicher?" und darin fragte ich: "Ist Malloc wieder am Start?"
Ich hatte den Eindruck, dass alle Wiedereinsteiger threadsicher sind.
Ist diese Annahme falsch?
Wiedereintretende Funktionen basieren nicht auf globalen Variablen, die in den C-Bibliotheksheadern verfügbar gemacht werden. Nehmen Sie zum Beispiel strtok () vs strtok_r () in C.
Einige Funktionen benötigen einen Platz zum Speichern eines "Work in Progress". Mit neu eingegebenen Funktionen können Sie diesen Zeiger im eigenen Speicher des Threads und nicht in einem globalen Speicher angeben. Da dieser Speicher nur für die aufrufende Funktion verfügbar ist, kann er unterbrochen und erneut eingegeben werden (Wiedereintritt). Da in den meisten Fällen ein gegenseitiger Ausschluss über das hinaus, was die Funktion implementiert, nicht erforderlich ist, wird dies häufig als solche angesehen fadensicher . Dies ist jedoch per Definition nicht garantiert.
errno ist jedoch ein etwas anderer Fall auf POSIX-Systemen (und ist in jeder Erklärung, wie dies alles funktioniert, der seltsame Punkt) :)
Kurz gesagt bedeutet Wiedereintritt häufig Thread-sicher (wie in "Verwenden Sie die Wiedereintrittsversion dieser Funktion, wenn Sie Threads verwenden"), aber Thread-sicher bedeutet nicht immer Wiedereintritt (oder umgekehrt). Wenn Sie sich mit Thread-Sicherheit und Parallelität befassen , müssen Sie über nachdenken. Wenn Sie ein Mittel zum Sperren und gegenseitigen Ausschließen bereitstellen müssen, um eine Funktion zu verwenden, ist die Funktion nicht von Natur aus threadsicher.
Es müssen jedoch auch nicht alle Funktionen untersucht werden. malloc()
muss nicht wiedereintrittsfähig sein, es hängt nicht von irgendetwas ab, das außerhalb des Bereichs des Einstiegspunkts für einen bestimmten Thread liegt (und ist selbst threadsicher).
Funktionen, die statisch zugewiesene Werte zurückgeben, sind ohne die Verwendung eines Mutex, Futex oder eines anderen atomaren Sperrmechanismus nicht threadsicher. Sie müssen jedoch nicht wieder eintreten, wenn sie nicht unterbrochen werden sollen.
dh:
static char *foo(unsigned int flags)
{
static char ret[2] = { 0 };
if (flags & FOO_BAR)
ret[0] = 'c';
else if (flags & BAR_FOO)
ret[0] = 'd';
else
ret[0] = 'e';
ret[1] = 'A';
return ret;
}
Wie Sie sehen können, wäre es eine Katastrophe, wenn mehrere Threads dies ohne irgendeine Art von Sperre verwenden. Es hat jedoch keinen Zweck, erneut einzutreten. Sie werden darauf stoßen, wenn dynamisch zugewiesener Speicher auf einer eingebetteten Plattform tabu ist.
Bei der rein funktionalen Programmierung bedeutet Wiedereintritt oft keine Thread-Sicherheit, sondern hängt vom Verhalten definierter oder anonymer Funktionen ab, die an den Funktionseintrittspunkt, die Rekursion usw. übergeben werden.
Eine bessere Möglichkeit, "threadsicher" zu machen, ist der gleichzeitige Zugriff , was die Notwendigkeit besser verdeutlicht.
TL; DR: Eine Funktion kann wiedereintrittsfähig, threadsicher sein, beides oder keines.
Die Wikipedia-Artikel zu Thread-Sicherheit und Wiedereintritt sind lesenswert. Hier einige Zitate:
Eine Funktion ist threadsicher, wenn:
Eine Funktion ist wiedereintrittsfähig, wenn:
Als Beispiele für einen möglichen Wiedereintritt gibt die Wikipedia das Beispiel einer Funktion an, die von Systeminterrupts aufgerufen werden soll: Angenommen, sie wird bereits ausgeführt, wenn ein anderer Interrupt auftritt. Aber denken Sie nicht, dass Sie sicher sind, nur weil Sie nicht mit Systeminterrupts codieren: Sie können Wiedereintrittsprobleme in einem Single-Thread-Programm haben, wenn Sie Rückrufe oder rekursive Funktionen verwenden.
Beispiele
(Leicht modifiziert aus den Wikipedia-Artikeln)
Beispiel 1: nicht threadsicher, nicht wiedereintrittsfähig
Beispiel 2: Thread-sicher, nicht wiedereintrittsfähig
Beispiel 3: nicht threadsicher, wiedereintrittsfähig
Beispiel 4: Gewindesicher, wiedereintrittsfähig
quelle
t = *x
, anruftswap()
,t
wird er überschrieben, was zu unerwarteten Ergebnissen führt.Das hängt von der Definition ab. Zum Beispiel verwendet Qt Folgendes:
aber sie warnen auch:
quelle