setjmp / longjmp в 64 битах

#c #linux #64-bit #x86

# #c #linux #64-разрядный #x86

Вопрос:

Я пытался использовать setjmp / longjmp в 64-битной Ubuntu, но он не работает должным образом, в то время как в 32-битной Ubuntu он работает нормально. Есть идеи, что происходит. Ниже приведен код, который я пытался выполнить.

На 64-битной версии он зависает в точке, где он возвращается после longjmp. В статье Википедии о setcontext говорится, что он не работает должным образом с 64 битами. Есть ли у нас такая же проблема с setjmp? Фактически, я пытался использовать setjmp, чтобы избежать проблемы с setcontext, но, похоже, у него такая же проблема на 64 битах.

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <string>
#include <setjmp.h>

#define NOFTHREADS 2

#define DATASIZE        500
#define SETSIZE         (DATASIZE / NOFTHREADS)  

int data[DATASIZE];
pthread_mutex_t sumMutex;
pthread_mutex_t prodMutex;
int sum;
double prod;
static jmp_buf buf;
int jmp_onced[NOFTHREADS 1];

#define lock pthread_mutex_lock
#define unlock pthread_mutex_unlock

void *SumThread( void *pParam )
{
  unsigned int tid = *((unsigned int*)(pParam));
  int si = tid * SETSIZE;
  int i, j, oi, local_sum;
  double local_prod;
  pthread_attr_t attr;

  if ( setjmp(buf) ) 
    printf( "%d: tid %u back! <<<<<<<<<n", getpid(), tid );
  if ( jmp_onced[tid] )
    goto end_this;

  printf( "%d: >>>>>>>>>>>>> tid %u, starting <<<<<<<<<<<<nn", getpid(), tid );

  for( oi = 0; oi < 5; oi   )
  {
    local_sum = 0;
    local_prod = 1.0;
    for( i = si; i < (si SETSIZE); i   )
    {
      local_sum = local_sum   data[i];
      if ( data[i ] )
      local_prod *= 0.005 * data[i];
    }

    lock( amp;sumMutex );
    sum  = local_sum;
    unlock( amp;sumMutex );

    lock( amp;prodMutex );
    prod *= local_prod;
    unlock( amp;prodMutex );
  }

  printf( "%d: !!!!!!!!!!!!!!tid %u done!!!!!!!!!!!!!!nn", getpid(), tid );
  jmp_onced[tid] = 1;
  longjmp( buf, 1 );

end_this:
  printf( "%d: ****** tid %u is exiting! ******n", getpid(), tid ); 
  return 0;
}

void real_main()
{
  pthread_t hThread[NOFTHREADS];
  int index[NOFTHREADS];
  int i, pid, err;
  time_t t1 = time(NULL);

  printf( "%d: Inside real_main, primary thread = %lx!n", getpid(), pthread_self() );
  for( i = 0; i < NOFTHREADS; i   )
  {
      index[i] = i;
      pthread_create( amp;hThread[i], NULL, SumThread, amp;index[i] ); 
  }
  for( i = 0; i < NOFTHREADS; i   )
      pthread_join( hThread[i], NULL );

  printf( "Sum of numbers from 1 to %d is %dn", DATASIZE, sum ); 
  printf( "Prod of numbers from 1 to %d is %gn", DATASIZE, prod );
  printf( "nn[[[[[ %d(child of %d): Time taken = %lu seconds ]]]]]nn", getpid(), getppid(), time(NULL) - t1 );
}

int main(int argc, char **argv)
{
  int pid, i, err;

  printf( "size of long is %dn", sizeof( long ) );

  sumMutex = PTHREAD_MUTEX_INITIALIZER;
  prodMutex = PTHREAD_MUTEX_INITIALIZER;
  printf( "pid = %d, @sumMutex = %lx, @prodMutex = %lxn", getpid(), (long)amp;sumMutex, (long)amp;prodMutex );   

  for( i = 0; i < DATASIZE; i   )
    data[i] = i 1;

  switch(pid = fork())
  {
  case -1:
    printf("fork failed");
    break;
  case 0: // Child
    printf( "Child pid() = %dn", getpid() );
    real_main();
    break;
  default:// Leader
    printf( "Parent pid() = %dn", getpid() );
    real_main();
  }

  printf( "getppid() = %d, getpid() = %dn", getppid(), getpid() );
  return 0;
}
 

Комментарии:

1. C C Повторная пометка в этом нет ничего.

2. Вам нужно объяснить, что вы подразумеваете под «это не работает должным образом».

3. Рассматривали ли вы возможность переписать код так, чтобы а) вам не нужен longjmp etc и б) вам не нужен goto ?

4. Эд Хил, просто тестировал функциональность setjmp и longjmp для какой-то цели. Это всего лишь экспериментальный код.

Ответ №1:

Вам нужно использовать отдельный jmp_buf для каждого потока. В настоящее время вы повторно используете тот же самый.

Комментарии:

1. Спасибо, Алан. Это была именно проблема. Теперь он работает нормально: -p!

2. Да, в общем, нет особого смысла иметь буфер перехода в качестве статической переменной. Просто объявите его в стеке в функции, которая его использует.

Ответ №2:

Если вы не объявляете свои локальные переменные volatile и изменяете их после вызова setjmp() , то они не гарантированно сохраняются при вызове longjmp() .

(7.13.2.1/ 3 в стандарте C99.)

Но, похоже, это здесь не применимо, поскольку si и tid не изменены.

Комментарии:

1. Интересно, посмотрим на это.

2. Конечно, нет. tid и si не изменяются после setjmp

3. Спецификация Singhle UNIX также описывает это .