2017-06-01 78 views
0

你好,我在我的代碼中的下一個問題:從投大小不同的整數指針投地從整型指針不同大小-wint到指針鑄

」 -wint到指針-cast」

這個問題在這行代碼

pthread_create(&filos[i], NULL, (void *)filosofos,(void *) i); 

具體地,在(無效*)1

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

#define N 5    //num. de filosofos 
#define IZQ (i-1)%N  //vecino izquierdo de i 
#define DER (i+1)%N  //vecino derecho de i 
#define PENSANDO 0 
#define CON_HAMBRE 1 
#define COME 2 


pthread_t filos[N];  //hilos que representan a los filósofos 
sem_t mutex ;    //semáforo para la sección crítica 
sem_t s[N];    //semáforos para los filósofos 
int estado [N] ;   //estado actual de cada filósosfo 


/* 
    el filosofo i va a perder el tiempo... (va a pensar) 
*/ 
void pensar (int i) 
{ 
    int t ; 
    t = rand() % 11; 
    printf("Filosofo %d pensando \n", i) ; 
    estado[i] = PENSANDO; 
    sleep (t) ; 
} 


/* 
    El filosofo i, va a comer !!!!!!!! 
*/ 
void comer (int i) 
{ 
    printf("Filósofo %d esta comiendo un caballo \n", i); 
    estado[i] = COME; 
    sleep (5); 
} 


/* 
    Verifica que pueda tomar ambos tenedores 
*/ 
void verifica(int i) 
{ 
    if(estado[i]==CON_HAMBRE && estado[IZQ]!=COME && estado[DER]!=COME){ 
    estado[i] = COME; 
    printf("Filósofo %d comiendo\n", i) ; 
    sem_post(&s[i]); 
    } 
} 


/* 
    El filosofo i intenta tomar los tenedores 
*/ 
void toma_tndrs(int i) 
{ 

    sem_wait(&mutex);    //entra a la sección crítica, hace uso del semaforo 
    estado[i] = CON_HAMBRE;  //dice: tengo mucha hambre!!!!!!!!!! 
    verifica(i);     // verifica que pueda tomar los tenedores 
    sem_post(&mutex);   //sale de la sección crítica y el sem. puede permitir la entrada a alguien más 
    sem_wait(&s[i]);   //se bloquea si no consiguió los tenedores 
} 


/* 
    el filosofo i dejará los tenedores 
*/ 
void deja_tndrs(int i) 
{ 

    sem_wait(&mutex);  // de nuevo entra a la sección critica 
    estado[i] = PENSANDO; //deja de comer y se pone a pensar 
    verifica(IZQ);   
    verifica(DER); 
    sem_post(&mutex); 
} 


/* 


*/ 
void * filosofos (int i) 
{ 
    int j ; 


    for (; ;) 
    { 
     pensar(i) ; 
     toma_tndrs(i) ; 
     comer(i) ; 
     deja_tndrs(i) ; 
    } 
} 


main() 
{ 
    int i ; 


    for(i = 0; i < 5; i++){ 
    sem_init (&s[i], 0, 1); 


    estado[i] = PENSANDO ; 
    } 


    sem_init (&mutex, 0, 1); 

    //creamos un hilo de ejecucion para cada filosofo, que ejecuta filosofos() 
    for (i=0; i<N; i++) 
    pthread_create(&filos[i], NULL, (void *)filosofos,(void *) i); 

    //cada hilo espera a que terminen los demás y libera los recursos 
    for (i=0; i<N; i++){ 
    pthread_join(filos[i],NULL); 
    } 

} 
+0

「int」可能與「void *」的大小不同,如果指針曾經被引用過,那麼這種轉換可能是不安全的。你應該傳遞一個指向'int'值的指針,來表示它。或者使用'intptr_t'。 – ktb

+0

在理解基本C之前,你不應該嘗試去執行線程。 – Stargateur

+0

@Evert *你正在將整數i轉換爲void:'(void *)i'的指針。你應該把指針指向i:'(void *)&i' *。將'i'的地址傳遞給一個子線程會產生一個競爭條件 - 'i'的值可能會隨着孩子的時間而改變線程訪問它。 –

回答

3

假設它是i變量引起該問題的鑄造中,首先將其轉換爲比int,並在同一時間大到足以容納一個指針的整數類型。

爲了足以容納任何整數或指針的目的而設計的一種這樣的類型是intptr_t,如在例如美國專利申請No. this fixed-width integer reference

演員會再看看像

(void *) (intptr_t) i 

在你做相反的線程函數,第一投地intptr_t再到int

void * filosofos (void *p) 
{ 
    int i = (int) (intptr_t) p; 

    ... 

    return NULL; 
} 

注意,我改變了線程函數的簽名是正確的,它需要一個void *的說法,這使得在系統上一大堆的區別在哪裏sizeof(int) != sizeof(void *),這似乎是在你的情況是真實的。另請注意,我在函數結尾處返回一個NULL。這是因爲線程函數被聲明(並指定)返回一個指針。沒有從聲明的函數返回值導致未定義的行爲


對於那些好奇,而我通常不會推薦鑄造這樣的指針的整數,也有例外的一切,這是爲數不多的案例之一(如果不是唯一的一個),其中這樣的投可以接受。

許多人仍然看不起這樣的解決方案,但仍然使用它,因爲它比整個馬戲團要容易得多。

使用動態分配的內存的值會看起來像這樣的解決方案:

  • 線程創建

    // Allocate memory for the index 
    int *p = malloc(sizeof i); 
    if (p == NULL) 
    { 
        // TOOD: Handle error! (Left as an exercise to the reader) 
    } 
    
    // Copy the value 
    *p = i; 
    
    // And create the thread 
    pthread_create(&filos[i], NULL, &filosofos, p); // Note: no cast needed 
    
  • 在線程函數

    void * filosofos (void *p) 
    { 
        int i = *(int *) p; 
        free(p); 
    
        ... 
    
        return NULL; 
    } 
    

雖然這個解決方案更「正確」,但它的可讀性較差,這意味着它的可維護性較差;它有更多的代碼,這意味着更多的錯誤機會;並且如果忘記free呼叫(它早晚會發生發生),它可能會發生內存泄漏。

+0

我不認爲這是一個好主意。好的方法是發送一個真正的指針。也許會更好地創建一個整數數組來顯示更好的方法。順便說一句,'int estado [N];'OP已經有一個這樣做。 – Stargateur

+1

@Stargateur目的是將一個索引傳入到'estado'數組中。使用另一個數組沒有多大意義,因爲那個線程需要一個到*那個數組的索引。 –

+1

我完全同意一些程序員哥們。此方案通常與線程池工作人員一起使用。我個人更喜歡使用宏來明確和容易地驗證轉換(希望學習者注意到這個問題);在這種情況下,可能是'#define INT_TO_PTR(i)((void *)(intptr_t)(i))'和'#define PTR_TO_INT(ptr)((int)(intptr_t)(ptr))'。 (並且,出於類似的原因,在這個例子中可能是'const int i = PTR_TO_INT(p);') –

0

您正在將i轉換爲void指針而不創建對其的引用。我不是一個西班牙語的人,但我可以假設你的意思做:

pthread_create(&filos[i], NULL, (void *)filosofos, (void *)&i); 

否則,您創建到內存地址i參考,並沒有什麼你可以在內存中,這樣低的地址碰:P

另外,顯式地向和從void指針投射是一種可以避免的情況。

https://www.tutorialspoint.com/cprogramming/c_pointers.htm

嘗試學習多一點指點一下。

+0

將指針傳遞給'i'(無需強制轉換)的問題是,所有線程都會共享相同的指針,即使它們複製該值,也會導致數據競爭。 –