Ich schrieb einen Code, um einige Threads zu erstellen und wann immer einer der Threads einen neuen Thread erstellt wird, um es zu ersetzen. Da ich mit Pthreads keine sehr große Anzahl von Threads (> 450) erstellen konnte, habe ich stattdessen den Klon-Systemaufruf verwendet. (Bitte beachten Sie, dass ich die Auswirkungen einer so großen Anzahl von Threads weiß, aber dieses Programm soll nur das System belasten).
Da clone() die Angabe des Stack-Bereichs für den untergeordneten Thread als Parameter erfordert, mallociere ich den erforderlichen Stapelspeicherplatz für jeden Thread und befreie ihn, wenn der Thread fertig ist. Wenn ein Thread fertig ist, sende ich ein Signal an das Elternteil, um es davon zu benachrichtigen.Debugging Segmentierung Fehler in einem Multi-Thread (mit Klon) -Programm
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#define NUM_THREADS 5
unsigned long long total_count=0;
int num_threads = NUM_THREADS;
static int thread_pids[NUM_THREADS];
static void *thread_stacks[NUM_THREADS];
int ppid;
int worker() {
int i;
union sigval s={0};
for(i=0;i!=99999999;i++);
if(sigqueue(ppid, SIGUSR1, s)!=0)
fprintf(stderr, "ERROR sigqueue");
fprintf(stderr, "Child [%d] done\n", getpid());
return 0;
}
void sigint_handler(int signal) {
char fname[35]="";
FILE *fp;
int ch;
if(signal == SIGINT) {
fprintf(stderr, "Caught SIGINT\n");
sprintf(fname, "/proc/%d/status", getpid());
fp = fopen(fname,"r");
while((ch=fgetc(fp))!=EOF)
fprintf(stderr, "%c", (char)ch);
fclose(fp);
fprintf(stderr, "No. of threads created so far = %llu\n", total_count);
exit(0);
} else
fprintf(stderr, "Unhandled signal (%d) received\n", signal);
}
int main(int argc, char *argv[]) {
int rc, i; long t;
void *chld_stack, *chld_stack2;
siginfo_t siginfo;
sigset_t sigset, oldsigset;
if(argc>1) {
num_threads = atoi(argv[1]);
if(num_threads<1) {
fprintf(stderr, "Number of threads must be >0\n");
return -1;
}
}
signal(SIGINT, sigint_handler);
/* Block SIGUSR1 */
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
if(sigprocmask(SIG_BLOCK, &sigset, &oldsigset)==-1)
fprintf(stderr, "ERROR: cannot block SIGUSR1 \"%s\"\n", strerror(errno));
printf("Number of threads = %d\n", num_threads);
ppid = getpid();
for(t=0,i=0;t<num_threads;t++,i++) {
chld_stack = (void *) malloc(148*512);
chld_stack2 = ((char *)chld_stack + 148*512 - 1);
if(chld_stack == NULL) {
fprintf(stderr, "ERROR[%ld]: malloc for stack-space failed\n", t);
break;
}
rc = clone(worker, chld_stack2, CLONE_VM|CLONE_FS|CLONE_FILES, NULL);
if(rc == -1) {
fprintf(stderr, "ERROR[%ld]: return code from pthread_create() is %d\n", t, errno);
break;
}
thread_pids[i]=rc;
thread_stacks[i]=chld_stack;
fprintf(stderr, " [index:%d] = [pid:%d] ; [stack:0x%p]\n", i, thread_pids[i], thread_stacks[i]);
total_count++;
}
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
while(1) {
fprintf(stderr, "Waiting for signal from childs\n");
if(sigwaitinfo(&sigset, &siginfo) == -1)
fprintf(stderr, "- ERROR returned by sigwaitinfo : \"%s\"\n", strerror(errno));
fprintf(stderr, "Got some signal from pid:%d\n", siginfo.si_pid);
/* A child finished, free the stack area allocated for it */
for(i=0;i<NUM_THREADS;i++) {
fprintf(stderr, " [index:%d] = [pid:%d] ; [stack:%p]\n", i, thread_pids[i], thread_stacks[i]);
if(thread_pids[i]==siginfo.si_pid) {
free(thread_stacks[i]);
thread_stacks[i]=NULL;
break;
}
}
fprintf(stderr, "Search for child ended with i=%d\n",i);
if(i==NUM_THREADS)
continue;
/* Create a new thread in its place */
chld_stack = (void *) malloc(148*512);
chld_stack2 = ((char *)chld_stack + 148*512 - 1);
if(chld_stack == NULL) {
fprintf(stderr, "ERROR[%ld]: malloc for stack-space failed\n", t);
break;
}
rc = clone(worker, chld_stack2, CLONE_VM|CLONE_FS|CLONE_FILES, NULL);
if(rc == -1) {
fprintf(stderr, "ERROR[%ld]: return code from clone() is %d\n", t, errno);
break;
}
thread_pids[i]=rc;
thread_stacks[i]=chld_stack;
total_count++;
}
fprintf(stderr, "Broke out of infinite loop. [total_count=%llu] [i=%d]\n",total_count, i);
return 0;
}
Ich habe paar Arrays Spur des Kindprozesses pid und der Stapelbereich Basisadresse zu halten verwendet
(es für die Freigabe):
Der Code ist unten angegeben.
Wenn ich dieses Programm starte, wird es nach einiger Zeit beendet. Das Ausführen mit gdb sagt mir, dass einer der Threads einen SIGSEGV (segmentation fault) bekommt. Aber es ist gibt mir keine Stelle, ist die Ausgabe ähnlich der folgenden:
Program received signal SIGSEGV, Segmentation fault.
[Switching to LWP 15864]
0x00000000 in ??()
Ich habe versucht, es unter valgrind mit dem folgenden Befehl ausgeführt wird:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes -v --num-callers=20 --track-fds=yes ./a.out
Aber es hält ohne Probleme läuft unter Valgrind.
Ich bin verwirrt, wie dieses Programm debuggen. Ich hatte das Gefühl, dass dies ein Stapelüberlauf oder etwas anderes sein könnte, aber das Erhöhen der Stapelgröße (bis zu 74 KB) hat das Problem nicht gelöst.
Meine einzige Frage ist warum und wo ist die Segmentierung Fehler oder wie dieses Programm zu debuggen.
ehrlich zu sein, ich bin über Klonfunktion unwissend, aber ich habe dies in OpenMP gesehen. Haben Sie versucht, die Größe der Stackgröße zu ändern, ulimit -s – Anycorn