I'm messing with the stack size because I want to make a large number of threads, sometimes greater than 1000, for the purpose of testing for deadlocks and such. The standard stack size limits me, on my machine, to about 387 threads.
And, yes, I definitely get the segfault on gdb. Sometimes it occurs in my code, sometimes it occurs in the "compiler code". And it moves around, depending on what code I have enabled. Here's my thread function, and yes, it's frickin nasty with all of the #if's at this point.
Code:
void *DoStuff(void* theData) {
int loop = 0;
int valueToWait = 0;
int i, j;
int myCount;
int val;
thread_data * data = (thread_data *) theData;
my_deque * deque = data->deque;
int victim;
#ifdef DOSTEAL
unsigned int t;
long oldAge;
#ifdef POPTOPHERE
unsigned int localBot;
long newAge;
#endif /* POPTOPHERE */
#endif /* DOSTEAL */
#ifndef NOARRAY
int threads[NUM_THREADS - 1];
#endif
while (1) {
#ifdef DEBUG
if (DEBUG >= 1)
printf("thread %5i approaching barrier in loop %i. numArrived %i\n", data->id, loop, numArrived);
#endif
// barrier
valueToWait = 1 - valueToWait;
pthread_mutex_lock(&mut);
numArrived++;
myCount = numArrived;
// wait for the signal, man
while ((allDie == 0) && (canGo != valueToWait)) {
pthread_cond_wait(&cond, &mut);
}
pthread_mutex_unlock(&mut);
// is it time to go?
if (allDie != 0) {
#ifdef DEBUG
if (DEBUG >= 1)
printf("thread %5i dying in loop %i\n", data->id, loop);
#endif
pthread_exit(NULL);
break;
}
// do some work
data->writes = 0;
data->misses = 0;
data->stealAttempts = 0;
data->steals = 0;
#ifndef SKIPNORMAL
while (1) {
j = (int)(deque->back);
if (j <= 0)
break;
val = (int)(my_deque_pop_bottom(deque));
// printf("j: %i val: %i datum->age: %u data[j]: %i\n", j, val, datum->age, (int)(datum->data[j]));
if (val == 0) {
deque->data[j-1] = data->id;
data->writes++;
}
else if (val == -1)
my_deque_push_bottom(deque, 0);
else if (val == (int)NIL) {
// printf("Thread %5i got a NIL for slot %5i in loop %i\n", datum->id, j, loop);
// break;
}
else
break;
}
#endif /* SKIPNORMAL */
#ifndef SKIPSTEAL
// now, try to steal, yo!
{
// set up my list of threads I've used
#ifndef SKIPMAKEARRAY
for (j = 0; j < NUM_THREADS - 1; j++) {
if (j < data->id-1)
threads[j] = j;
else
threads[j] = j+1;
}
// print the array to screen
#ifdef PRINTTHREADARRAY
printf("Thread %5i's threads array:\n", data->id);
for (j = 0; j < NUM_THREADS - 1; j++)
printf(" threads[%6i]: %6i\n", j, threads[j]);
#endif /* PRINTTHREADARRAY */
#endif /* SKIPMAKEARRAY */
// go through all the threads
for (j = 0; j < NUM_THREADS - 1; j++) {
// pick a victim (pictim!)
#ifdef RANDOM
i = (rand() % (NUM_THREADS - 1 - j));
victim = threads[i];
if (victim == INT_MIN) {
printf("something's wrong, sherlock!\n");
continue;
}
// swap victim with last number in list
threads[i] = threads[NUM_THREADS - 2 - j]; /* changed line of code */
threads[NUM_THREADS - 2 - j] = INT_MIN; // put a dummy value in so we know it's bad /* changed line of code */
#else
victim = j;
#endif /* RANDOM */
#ifdef DOSTEAL
// now, start from top and try to steal
while (1) {
oldAge = threadData[victim].deque->age;
t = top(oldAge);
if (threadData[victim].deque->back > t) {
data->stealAttempts++;
// don't pop it if it's a sentinel
if (threadData[victim].deque->data[t] != 0)
continue;
#ifdef POPTOPHERE
/* this section of code does the popping right here */
localBot = threadData[victim].deque->back;
if (localBot <= t) {
val = NIL;
goto PopDone;
}
val = threadData[victim].deque->data[t];
newAge = oldAge + 1;
// can do a ++ here because we are only incrementing the top
newAge = __sync_val_compare_and_swap(&(threadData[victim].deque->age), oldAge, newAge);
if (oldAge != newAge)
val = NIL;
#else
/* this section of code tries to use the pop function */
// make sure age hasn't changed, just for kicks
// this reduces possibility for a race, but doesn't eliminate it
if (oldAge != threadData[victim].deque->age)
continue;
val = (int)(my_deque_pop_top(threadData[victim].deque));
#endif /* POPTOPHERE */
PopDone:
if (val == 0) {
threadData[victim].deque->data[t] = data->id;
data->writes++;
data->steals++;
}
// removed this because this caused threads to quit when they got rejected
// which isn't always the right thing to do
// else // stop stealing from this guy
// break;
}
else // this guy is already finished
break;
}
#endif /* DOSTEAL */
}
}
#endif /* SKIPSTEAL */
// calculate number of missed writes
for (i = 0; i < MY_DEQUE_ARRAY_SIZE; i++) {
if (deque->data[i] == 0)
data->misses++;
}
// now, print out the results
#ifndef SKIPPRINT
printf("Thread %5i done with loop %i. Writes: %5i Steals Attempts: %10li Missed Writes: %5i\n", data->id, loop, data->writes, data->steals, data->misses);
#endif
loop++;
}
}
Sometimes it segfaults in the thread, sometimes it segfaults when trying to join the to the threads to end program execution. In case you are curious, yes, this code is for an assignment, and I hope that's kosher to ask on here. I'm more curious about the segfault than any particular way to solve the programming assignment.