Ich komme zu dem Code in einem Bit, das beweist, dass Sie eine Race-Bedingung hatten. Ich werde ein paar verschiedene Möglichkeiten hinzufügen, um es auszulösen, damit Sie sehen können, wie das funktioniert. Ich tue dies auf Linux und -std vorbei = gnu99 als param dh
gcc -Wall -pedantic -lpthread -std=gnu99 semaphore.c -o semtex
Hinweis auf gcc. In Ihrem ursprünglichen Beispiel (unter der Annahme von Linux) war ein fataler Fehler, den Sie hatten, nicht, den Semaphor zu entfernen. Wenn Sie den folgenden Befehl ausführen, können Sie einige davon sitzen auf Ihrem Computer sehen
ls -la /dev/shm/sem.*
Sie müssen sicherstellen, dass es keine alten Semaphore auf dem Dateisystem sitzt vor Ihrem Programm läuft oder Sie Kommissionierung bis am Ende der letzte Einstellungen aus dem alten Semaphor. Sie müssen sem_unlink
verwenden, um aufzuräumen.
Um es zu verwenden, verwenden Sie bitte folgendes.
rm /dev/shm/sem.semtex;./semtex
Ich mache bewusst sicher, dass die Semaphore vor dem Laufen, weil nicht da ist, wenn Sie ein Deadlock haben kann es sich um gelassen werden und die bewirkt, dass alle möglichen Probleme beim Testen.
Nun, wenn ich die sempahore öffnete, machte ich die Zählung 3. Ich erwartet hatte , dass dies nicht funktionieren würde, und ich würde Race-Bedingung erhalten, weil jeder Faden Dekrementieren der Zählung nun in der Lage ist.
Sie hatte eine Race-Bedingung, aber manchmal ist C so verdammt schnell Dinge können erscheinen zu arbeiten, weil Ihr Programm alles, was es in der Zeit, das Betriebssystem auf den Thread zugeordnet ist, dh das Betriebssystem nicht tat getan werden muss, bekommen preempt es an einem wichtigen Punkt.
Dies ist einer dieser Fälle, die Race-Bedingung ist da, Sie müssen nur ein wenig schielen, um es zu sehen. Im folgenden Code können Sie einige Parameter optimieren, um einen Deadlock, eine korrekte Verwendung und ein nicht definiertes Verhalten zu sehen.
#define INITIAL_SEMAPHORE_VALUE CORRECT
Der Wert INITIAL_SEMAPHORE_VALUE
kann drei Werte annehmen ...
#define DEADLOCK 0
#define CORRECT 1
#define INCORRECT 2
Ich hoffe, sie sind selbsterklärend. Sie können auch zwei Methoden verwenden, um zu bewirken, dass die Wettlaufbedingung das Programm sprengt.
#define METHOD sleep
Stellen Sie den METHOD
zu spin
und Sie können mit dem SPIN_COUNT
und finden Sie heraus zu spielen, wie oft die Schleife ausgeführt werden können, bevor Sie tatsächlich sehen, ein Problem, das C ist, kann es noch viel zu tun, bevor es vorbelegt wird . Der Code enthält den größten Teil der Informationen, die Sie darin benötigen.
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define DEADLOCK 0 // DEADLOCK
#define CORRECT 1 // CORRECT
#define INCORRECT 2 // INCORRECT
/*
* Change the following values to observe what happen.
*/
#define INITIAL_SEMAPHORE_VALUE CORRECT
//The next value provides to two different ways to trigger the problem, one
//using a tight loop and the other using a system call.
#define METHOD sleep
#if (METHOD == spin)
/* You need to increase the SPIN_COUNT to a value that's big enough that the
* kernel preempts the thread to see it fail. The value set here worked for me
* in a VM but might not work for you, tweak it. */
#define SPIN_COUNT 1000000
#else
/* The reason we can use such a small time for USLEEP is because we're making
* the kernel preempt the thread by using a system call.*/
#define USLEEP_TIME 1
#endif
#define TOT_THREADS 10
static int g = 0;
static int ret = 1729;
sem_t *semaphore;
void *myThreadFun(void *vargp) {
int myid = (int)vargp;
int w = 0;
static int s = 0;
if((w = sem_wait(semaphore)) != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
abort();
};
/* This is the interesting part... Between updating `s` and `g` we add
* a delay using one of two methods. */
s++;
#if (METHOD == spin)
int spin = 0;
while(spin < SPIN_COUNT) {
spin++;
}
#else
usleep(USLEEP_TIME);
#endif
g++;
if(s != g) {
fprintf(stderr, "Fatal Error: s != g in thread: %d, s: %d, g: %d\n", myid, s, g);
abort();
}
printf("Thread ID: %d, Static: %d, Global: %d\n", myid, s, g);
// It's a false sense of security if you think the assert will fail on a race
// condition when you get the params to sem_open wrong It might not be
// detected.
assert(s == g);
if((w = sem_post(semaphore)) != 0) {
fprintf(stderr, "Error: %s\n", strerror(errno));
abort();
};
return &ret;
}
int main(void){
int i;
void *status;
const char *semaphore_name = "semtex";
pthread_t tids[TOT_THREADS];
if((semaphore = sem_open(semaphore_name, O_CREAT, 0644, INITIAL_SEMAPHORE_VALUE)) == SEM_FAILED) {
fprintf(stderr, "Fatal Error: %s\n", strerror(errno));
abort();
}
for (i = 0; i < TOT_THREADS; i++) {
pthread_create(&tids[i], NULL, myThreadFun, (void *) (intptr_t) i);
}
for (i = 0; i < TOT_THREADS; i++) {
pthread_join(tids[i], &status);
assert(*(int*)status == 1729);
}
/*The following line was missing from your original code*/
sem_unlink(semaphore_name);
pthread_exit(0);
}
Was ist der Rückgabewert von 'sem_open (" Semaphor ", O_CREAT, 0644, 1);'? – EOF
Haben Sie die Manpage für 'sem_open()' angeschaut, vor allem, was die Bedeutung des Rückgabewertes ist? – EOF
Es ist nicht gleich SEM_FAILED – Semantics