Mutex-Lock-Threads

Lesezeit: 6 Minuten

Benutzeravatar von resting
ruhen

Bin neu in der Multithread-/Prozessprogrammierung. Also hier ist, was ich klären muss.

A-Code verarbeiten

pthread_mutex_lock()
    pthread_create(fooAPI(sharedResource)) //fooAPI creates another thread with shared resource that shares across processes.
pthread_mutex_unlock()

Mit dem obigen Pseudocode kann Prozess B zugreifen sharedResource wenn Mutex nicht entsperrt ist?

Wie kann ich korrekt auf die sharedResource von Prozess B zugreifen?

Gibt es ein klares visuelles Diagramm, das die Beziehung zwischen Mutexe, Threads und Prozessen erklärt?

  • Vielleicht sollten wir den Titel dieser Frage ändern in “Mutex sperrt Threads mit pthread_mutex_lock() in C” ?– oder so ähnlich, um die Frage besser durchsuchbar zu machen und gleich im Vorfeld mehr Klarheit zu haben?

    – Gabriel Staples

    30. Mai 2021 um 4:10 Uhr


  • Verwandte Frage, die ich gerade gestellt habe: Mutexe/Sperren in C: C11 mtx_lock() vs pthread_mutex_lock()

    – Gabriel Staples

    24. Juni 2021 um 0:29 Uhr

Brians Benutzeravatar
Brian

Was Sie tun müssen, ist pthread_mutex_lock aufzurufen, um einen Mutex wie folgt zu sichern:

pthread_mutex_lock(&mutex);

Sobald Sie dies tun, werden alle anderen Anrufe ausgeführt pthread_mutex_lock(mutex) wird nicht zurückkehren, bis Sie anrufen pthread_mutex_unlock in diesem Thread. Wenn Sie also versuchen, pthread_create aufzurufen, können Sie einen neuen Thread erstellen, und dieser Thread kann (fälschlicherweise) die gemeinsam genutzte Ressource verwenden. Du solltest anrufen pthread_mutex_lock aus deinem Inneren fooAPI Funktion, und das bewirkt, dass die Funktion wartet, bis die gemeinsam genutzte Ressource verfügbar ist.

Also hättest du so etwas:

#include <pthread.h>
#include <stdio.h>

int sharedResource = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* fooAPI(void* param)
{
    pthread_mutex_lock(&mutex);
    printf("Changing the shared resource now.\n");
    sharedResource = 42;
    pthread_mutex_unlock(&mutex);
    return 0;
}

int main()
{
    pthread_t thread;

    // Really not locking for any reason other than to make the point.
    pthread_mutex_lock(&mutex);
    pthread_create(&thread, NULL, fooAPI, NULL);
    sleep(1);
    pthread_mutex_unlock(&mutex);

    // Now we need to lock to use the shared resource.
    pthread_mutex_lock(&mutex);
    printf("%d\n", sharedResource);
    pthread_mutex_unlock(&mutex);
}

Bearbeiten: Die prozessübergreifende Verwendung von Ressourcen folgt demselben grundlegenden Ansatz, aber Sie müssen den Speicher Ihrem anderen Prozess zuordnen. Hier ist ein Beispiel mit shmem:

#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/wait.h>

struct shared {
    pthread_mutex_t mutex;
    int sharedResource;
};

int main()
{
    int fd = shm_open("/foo", O_CREAT | O_TRUNC | O_RDWR, 0600);
    ftruncate(fd, sizeof(struct shared));

    struct shared *p = (struct shared*)mmap(0, sizeof(struct shared),
        PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

    p->sharedResource = 0;

    // Make sure it can be shared across processes
    pthread_mutexattr_t shared;
    pthread_mutexattr_init(&shared);
    pthread_mutexattr_setpshared(&shared, PTHREAD_PROCESS_SHARED);

    pthread_mutex_init(&(p->mutex), &shared);

    int i;
    for (i = 0; i < 100; i++) {
        pthread_mutex_lock(&(p->mutex));
        printf("%d\n", p->sharedResource);
        pthread_mutex_unlock(&(p->mutex));
        sleep(1);
    }

    munmap(p, sizeof(struct shared*));
    shm_unlink("/foo");
}

Das Schreiben des Programms zum Vornehmen von Änderungen an p->sharedResource bleibt dem Leser als Übung überlassen. 🙂

Übrigens vergessen zu beachten, dass der Mutex das Attribut PTHREAD_PROCESS_SHARED gesetzt haben muss, damit pthreads prozessübergreifend funktionieren.

  • Das ist sehr klar. Könnten Sie auch ein Beispiel dafür angeben, wie Prozess B, bei dem es sich um eine andere Anwendung handelt, auf die gemeinsam genutzte Ressource zugreifen könnte?

    – ausruhen

    15. Februar 2013 um 4:56 Uhr

F1.) Angenommen, Prozess B versucht, denselben Mutex zu übernehmen, den Sie in Prozess A gesperrt haben (Sie haben das aus Ihrem Pseudocode gelassen), dann kann Prozess B nicht auf sharedResource zugreifen, während der Mutex gesperrt ist, da er darauf wartet, den Mutex zu sperren bis es von Prozess A freigegeben wird. Es wird von der Funktion mutex_lock() zurückgegeben, wenn der Mutex gesperrt ist (oder wenn ein Fehler auftritt!)

Q2.) Stellen Sie in Prozess B sicher, dass Sie den Mutex immer sperren, auf die gemeinsam genutzte Ressource zugreifen und dann den Mutex entsperren. Überprüfen Sie außerdem den Rückgabecode der Routine mutex_lock( pMutex ), um sicherzustellen, dass Sie tatsächlich Eigentümer des Mutex sind, und entsperren Sie den Mutex NUR, wenn Sie ihn gesperrt haben. Machen Sie dasselbe von Prozess A.

Beide Prozesse sollten beim Zugriff auf den Mutex grundsätzlich dasselbe tun.
lock() Wenn die Sperre erfolgreich ist, dann { access sharedResource unlock() }

Q3.) Ja, es gibt viele Diagramme: =)
https://www.google.se/search?q=mutex+thread+process&rlz=1C1AFAB_enSE487SE487&um=1&ie=UTF-8&hl=en&tbm=isch&source=og&sa=N&tab=wi&ei=ErodUcSmKqf54QS6nYDoAw&biw=1200&bih=1730&sei=FbodUbPATbB4

Ein Prozess besteht aus mindestens einem Thread (denken Sie an die Hauptfunktion). Code mit mehreren Threads erzeugt nur mehr Threads. Mutexe werden verwendet, um Sperren um gemeinsam genutzte Ressourcen zu erstellen, um Datenbeschädigungen / unerwartetes / unerwünschtes Verhalten zu vermeiden. Grundsätzlich sieht es eine sequentielle Ausführung in einem asynchronen Setup vor – die Anforderung dafür ergibt sich aus nicht konstanten, nicht atomaren Operationen auf gemeinsam genutzten Datenstrukturen.

Eine anschauliche Beschreibung, welche Mutexe der Fall von Personen (Threads) sein würden, die sich anstellen, um die Toilette zu besuchen (gemeinsame Ressource). Während eine Person (Thread) das Badezimmer benutzt, um sich zu entspannen (non-const non-atomic operation), sollte er/sie sicherstellen, dass die Tür verschlossen ist (mutex), da dies sonst dazu führen kann, dass sie in vollem Umfang erwischt wird (unerwünschtes Verhalten )

Das folgende Code-Snippet hilft Ihnen beim Verständnis des Mutex-Lock-Unlock-Konzepts. Versuchen Sie, den Code trocken auszuführen. (Weiterhin können Sie durch Variieren der Wartezeit und der Bearbeitungszeit Ihr Verständnis aufbauen).

Code für Ihre Referenz:

#include <stdio.h>
#include <pthread.h>

void in_progress_feedback(int);

int global = 0;
pthread_mutex_t mutex;
void *compute(void *arg) {

    pthread_t ptid = pthread_self();
    printf("ptid : %08x \n", (int)ptid);    

    int i;
    int lock_ret = 1;   
    do{

        lock_ret = pthread_mutex_trylock(&mutex);
        if(lock_ret){
            printf("lock failed(%08x :: %d)..attempt again after 2secs..\n", (int)ptid,  lock_ret);
            sleep(2);  //wait time here..
        }else{  //ret =0 is successful lock
            printf("lock success(%08x :: %d)..\n", (int)ptid, lock_ret);
            break;
        }

    } while(lock_ret);

        for (i = 0; i < 10*10 ; i++) 
        global++;

    //do some stuff here
    in_progress_feedback(10);  //processing-time here..

    lock_ret = pthread_mutex_unlock(&mutex);
    printf("unlocked(%08x :: %d)..!\n", (int)ptid, lock_ret);

     return NULL;
}

void in_progress_feedback(int prog_delay){

    int i=0;
    for(;i<prog_delay;i++){
    printf(". ");
    sleep(1);
    fflush(stdout);
    }

    printf("\n");
    fflush(stdout);
}

int main(void)
{
    pthread_t tid0,tid1;
    pthread_mutex_init(&mutex, NULL);
    pthread_create(&tid0, NULL, compute, NULL);
    pthread_create(&tid1, NULL, compute, NULL);
    pthread_join(tid0, NULL);
    pthread_join(tid1, NULL);
    printf("global = %d\n", global);
    pthread_mutex_destroy(&mutex);
          return 0;
}

1393390cookie-checkMutex-Lock-Threads

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy