2012-04-03 1 views
1
Linux

Das ist eine seltsame problem.I init sem und destory es zuerst, dann habe ich es in einem thread.then wieder init, kann ich es nicht aufwachen again.The Code ist:posix sem_post kann sem_wait nicht wecken wo die sem init im thread ist.

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <semaphore.h> 
#include <time.h> 
#include <assert.h> 
#include <errno.h> 
#include <signal.h> 
#include <pthread.h> 

sem_t sem; 
int key = 1; 

static void * 
wait_func() 
{ 
    printf("i'm wait\n"); 
    sem_wait(&sem); 
} 

static void * 
cancel_func(void *arg) 
{ 
    pthread_t tid = *(pthread_t *)arg; 
    if (key == 1) 
    { 
     sleep(1); 
     key = 0; 
    } 
    else 
     sleep(3); 
    if(pthread_cancel(tid) == 0) 
     printf("cancle!\n"); 

    sem_init(&sem, 0, 0); 
    sem_destroy(&sem); 
} 

int 
main(int argc, char *argv[]) 
{ 
    pthread_t wthread, cthread; 
    pthread_attr_t attr; 
    int i = 0; 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 

    sem_init(&sem, 0, 0); 

    while (i < 2) 
    { 
    //  sem_init(&sem, 0, 0); 

     pthread_create(&wthread, &attr, wait_func, NULL); 
     if (i < 1) 
      pthread_create(&cthread, &attr, cancel_func, &wthread); 
     if (key == 0) 
     { 
      sleep(2); 
      if (sem_post(&sem) == 0) 
       printf("post!\n"); 
      key = 1; 
     } 
     sleep(4); 
     ++i; 
    } 
    sleep(1000); 
} 

es jedoch sein Werk, das geändert sem_init in while-Schleife wie Kommentar Also ich zwei Programm straced habe, und finded 1) init in Thread, rief sem_post sys_futex nicht, wie diese:

nanosleep({2, 0}, i'm wait 

{2, 0}) = 0 schreiben (1, "post! \ N", 6post! ) = 6

2) init in Hauptprozess, sem_post Aufruf sys_futex, wie folgt aus:

nanosleep({2, 0}, i'm wait 

{2, 0}) = 0 futex (0x600dc0, FUTEX_WAKE_PRIVATE, 1) = 1 write (1, „post! \ n ", 6post! )

Dann dachte ich, das ist vielleicht ein Problem mit syscall.Ich habe Gdb verwendet, um zwei Programme in sem_post zu zerlegen. leider, 1) init in thread, es ruft auch syscall in sem_post; 2) verglichen ihre registry status wo rip ist syscall, das gleiche auch.

in thread: 
rax   0xca  202   //sys_futex 
rbx   0x3c0e61bbc0  257939323840 
rcx   0x0  0   //utime 
rdx   0x1  1   //val 
rsi   0x81  129   //op:private_wake 
rdi   0x600dc0 6294976  //sem uaddr 
in main process: 
rax   0xca  202 
rbx   0x3c0e61bbc0  257939323840 
rcx   0x0  0 
rdx   0x1  1 
rsi   0x81  129 
rdi   0x600da0 6294944 

Endlich habe ich keine Ahnung von diesem Problem.Bitte geben Sie mir einige Ratschläge, um die Lösung zu finden, danke.

+0

Ist das ein tatsächliches Problem? Wenn Sie nicht ständig Semaphore erzeugen und zerstören, gibt es kein Problem, oder? Abgesehen davon, mit der Statusvariable des gemeinsam genutzten Schlüssels, den Short-Schlägen und mehreren Threads, habe ich keine Ahnung, was Ihr Code eigentlich macht. Es tut mir leid, und ich bin bereit, korrigiert zu werden, aber das klingt wie 'Ich mache einige unrealistische und seltsame Dinge mit Semaphoren und ich bekomme seltsames Verhalten'. Wenn Sie das Semaphor erstellen und es nicht zerstören, geht es Ihnen gut, ja? –

+0

Ja, es kann jedes Mal wiederholen, verwenden Sie mein Beispiel code.Ich lese einige Man-Seite von sem_init sagte, dass nicht das gleiche sem in vielen Thread initiieren, aber ich bin nicht klar über den gleichen sem Punkt ein uaddr oder init sem var zweimal. Der Code ist nichts zu tun, nur sem_wait zufrieden zu machen.Trace assemblieren Code rufen Sie syscall (futex_wake) in der Tat, aber strace nicht dump diesen syscall, das ist seltsam. – user1310866

Antwort

0

Ich denke, dass Ihr Problem in dem Zugriff auf key liegt. Es gibt keine Garantie, dass der Zugriff auf gemeinsam genutzte Variablen atomar ist. Insbesondere könnte der Compiler das Lesen eines Wertes aus dem Speicher optimieren, so dass er keine Änderung des Wertes sieht, der in einem anderen Thread ausgeführt wird.

Um zu vermeiden, dass der Optimierer einsetzt, müssten Sie Ihre key Variable volatile deklarieren. Aber ich bin mir nicht sicher, dass die Art und Weise, wie Sie Ihr Programm geschrieben haben, garantieren würde, dass es Speicherbarrieren gibt, die garantieren würden, dass die Threads garantierte Änderungen und sind, dass der gleichzeitige Schreibvorgang nichts durcheinander bringt.

Moderne C11 hat auch _Atomic, um sicherzustellen, dass der Zugriff atomar ist. Aber C11 ist noch nicht vollständig implementiert (möglicherweise gibt es einige Compiler, die diese Funktion haben). Wenn es so wäre, gäbe es ein Problem mit Semaphoren, da C11 nur Mutexe und keine Semaphore als Sperrstrukturen hat. Wie diese beiden Merkmale zusammenwirken, ist noch nicht festgelegt.

+0

Sie bedeutet, gdb Schritt für Schritt verwerfen die Optimierung, so dass es Trace syscall wurde nicht tatsächlich in Exec entlang passiert? Ja, ur righ.i verifiziert dies durch systemtap.Ich verschwendete einen Tag, um herauszufinden, warum syscall passiert, aber nicht aufzeichnen. vielen Dank! – user1310866

Verwandte Themen