Reputation: 31
I'm having trouble finding the cause of this seg fault when calling pthread_create...
GDB is giving me Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bc741d in pthread_create@@GLIBC_2.2.5 () from /lib64/libpthread.so.0
I'll include the part of the code that calls it and the part of the code which includes the function the threads are calling.
int main(int argc, char **argv)
{
/*
* Declare local variables
*/
int i, j; // LK
pthread_t *cat[NUM_CATS]; // LK
pthread_t *lizard[NUM_LIZARDS]; // LK
/*
* Check for the debugging flag (-d)
*/
debug = 0;
if (argc > 1)
if (strncmp(argv[1], "-d", 2) == 0)
debug = 1;
/*
* Initialize variables
*/
numCrossingSago2MonkeyGrass = 0;
numCrossingMonkeyGrass2Sago = 0;
running = 1;
/*
* Initialize random number generator
*/
srandom( (unsigned int)time(NULL) );
/*
* Initialize locks and/or semaphores
*/
sem_init(&driveway, 0, 20); // LK
/*
* Create NUM_LIZARDS lizard threads
*/
// LK
for(i = 0; i < NUM_LIZARDS; i++) {
pthread_create(lizard[i], NULL, lizardThread, (void *)(&i));
}
And the function called by pthread_create...
void * lizardThread( void * param )
{
int num = *(int*)param;
if (debug)
{
printf("[%2d] lizard is alive\n", num);
fflush(stdout);
}
while(running)
{
lizard_sleep(num); // LK
sago_2_monkeyGrass_is_safe(num); // LK
cross_sago_2_monkeyGrass(num); // LK
lizard_eat(num); // LK
monkeyGrass_2_sago_is_safe(num); // LK
cross_monkeyGrass_2_sago(num); // LK
}
pthread_exit(NULL);
}
Upvotes: 0
Views: 2059
Reputation: 409196
You have the principle right, that you should pass a pointer to a pthread_t
as the first argument to the pthread_create
function.
The problem is that the pointers must actually point to something.
Normally when creating a single thread, you use a single pthread_t
variable (not a pointer!) and uses the address-of operator when calling pthread_create
. Like
pthread_t thread; // Creates a normal non-pointer variable
pthread_create(&thread, ...); // Pass the address of the variable, as a pointer to it
For your program you should do the same, pass pointers to actual pthread_t
instances using the &
operator. For this you first need to change the lizard
array to not be an array of pointers:
pthread_t lizard[NUM_LIZARDS]; // LK
Then use the address-of operator when creating the threads:
pthread_create(&lizard[i], NULL, lizardThread, (void *)(&i));
By using the address-of operator &
like this is emulating something called "call by reference".
There is however another problem in your code, that is much more subtle.
Because you pass a pointer to the loop variable i
when the thread function actually starts the loop might have iterated a couple of times which means the value of i
will not be correct when you dereference the pointer in the thread function. This is known as a data race or race condition.
The solution to this is to actually not pass a pointer, but the integer value itself. You do this by casting it to an intptr_t
(which is big enough to hold both integers and pointers) and casting that to a pointer:
pthread_create(&lizard[i], NULL, lizardThread, (void *) (intptr_t) i);
The intptr_t
type is part of the fixed-width integer types introduced in the C99 standard.
To use it you need to cast it back in the thread function:
int num = (int) (intptr_t) param;
Upvotes: 2
Reputation: 121397
The segfault is very likely because of passing uninitialized thread ID to pthread_create()
. The array lizard
isn't initialized.
Instead use an array:
pthread_t lizard[NUM_LIZARDS]; // LK
...
// LK
for(i = 0; i < NUM_LIZARDS; i++) {
pthread_create(&lizard[i], NULL, lizardThread, (void *)(&i));
}
Also, note that there's data race since you pass &i
to all threads. Instead you can use an array to fix the data race.
int arr[NUM_LIZARDS];
for(i = 0; i < NUM_LIZARDS; i++) {
arr[i] = i;
pthread_create(&lizard[i], NULL, lizardThread, &arr[i]);
}
Upvotes: 4