【问题标题】:cast to pointer from integer of different size -wint-to-pointer-cast从不同大小的整数转换为指针 -wint-to-pointer-cast
【发布时间】:2017-06-01 04:01:32
【问题描述】:

您好,我的代码中有下一个问题:

"从不同大小的整数转换为指针-wint-to-pointer-cast"

这个问题就在这行代码

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

具体在 (void *) i

#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);
  }

}

【问题讨论】:

  • int 的大小可能与void* 的大小不同,并且如果指针被引用,则该强制转换可能是不安全的。您应该传递一个指向 int 值的指针,然后进行转换。或使用intptr_t
  • 在了解基本 C 之前,你不应该尝试做线程。
  • @Evert 您将整数 i 转换为指向 void 的指针:(void *) i。您应该将指针转换为 i:(void *)&amp;i 不。将i 的地址传递给子线程会产生竞争条件 - i 的值可能会在子线程时发生变化访问它。
  • @AndrewHenle 啊,感谢您的澄清。

标签: c semaphore


【解决方案1】:

假设是 i 变量的转换导致问题,首先将其转换为大于 int 的整数类型,同时大到足以容纳指针。

一种这样的类型,其目的是为了足够大以容纳任何整数或指针,是intptr_t,在例如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。这是因为线程函数被声明(并指定)返回一个指针。不从声明的函数返回值会导致未定义的行为


对于那些好奇的人,虽然我通常不建议将整数转换为这样的指针,但任何事情都有例外,这是可以接受这种转换的少数情况之一(如果不是唯一的情况)。

许多人仍然看不起这样的解决方案,但仍然使用它,因为它比其他需要的整个 malloc-copy-free 马戏团更容易。

使用动态分配内存作为值的解决方案如下所示:

  • 线程创建

    // 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 调用(迟早会发生),则可能会发生内存泄漏。

【讨论】:

  • 我不认为展示这个是个好主意。好的方法是发送一个真正的指针。也许会更好地创建一个整数数组以显示更好的方法。顺便说一句,int estado [N]; OP 已经有人这样做了。
  • @Stargateur 目的是将estado数组的索引传递给线程。使用另一个数组没有多大意义,因为线程需要一个 that 数组的索引。
  • 我完全同意一些程序员老兄的观点。这种方案非常常用于线程池工作者。我个人更喜欢使用宏使转换变得明确且易于验证(希望学习者注意到这个问题);在这种情况下,可能是#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);。)
  • 虽然这个解决方案更“正确”,但它的可读性较差,这意味着它的可维护性较差不仅如此,malloc()/free() 解决方案很可能是性能瓶颈,因为它有效地将所有新启动的子线程通过堆单线程。它还影响新线程创建性能,因为子 free() 调用阻碍了父 malloc() 调用。更难维护、更容易出错、更慢的代码并不是我所说的做任何事情的“好方法”。
【解决方案2】:

您正在将 i 转换为 void 指针,而没有创建对它的引用。我不会说西班牙语,但我可以假设您打算这样做:

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

否则,您已经创建了对内存地址i 的引用,并且您在内存中没有任何可以触摸的低地址:P

另外,显式转换为 void 指针和从 void 指针转换是需要避免的。

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

尝试更多地了解指针。

【讨论】:

  • 将指针传递给i(不需要强制转换)的问题是所有线程将共享相同的指针,即使它们复制值也会导致数据-种族。
猜你喜欢
  • 1970-01-01
  • 2012-03-04
  • 2015-06-04
  • 2021-03-10
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 2014-03-20
相关资源
最近更新 更多