#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 также описывает это .