2017-06-01 57 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'(无需强制转换)的问题是,所有线程都会共享相同的指针,即使它们复制该值,也会导致数据竞争。 –