Multiple threads in C program - c

I'm writing a Unix application in C which uses multiple threads of control. I'm having a problem with the main function terminating before the thread it has spawned have a change to finish their work. How do I prevent this from happening. I suspect I need to use the pthread_join primitive, but I'm not sure how. Thanks!

Yes, you could use pthread_join() (see other anwers for how to do that). But let me explain the pthread model and show you another option.
In Unix, a process exits when the primary thread returns from main, when any thread calls exit() or when the last thread calls pthread_exit(). Based on the last option, you can simply have your main thread call pthread_exit() and the process will stay alive as long as at least one more thread is running.

Yes one of doing this is to use pthread_join function: that's assuming your thread is in "joinable" state.
pthread_create: after this function returns control, your thread will be executing your thread function.
after pthread_create, use the tid from pthread_create to pthread__join.
If your thread is detached, you must use some other technique e.g. shared variable, waiting on signal(s), shared queue etc.
Great reference material available here.

There are a number of different ways you can do this, but the simplest is to call pthread_exit() before returning from main().
Note that this technique works even if the thread you want to wait for is not joinable.

You may want to look at this page:
http://publib.boulder.ibm.com/iseries/v5r2/ic2924/index.htm?info/apis/users_25.htm
rc = pthread_create(&thread, NULL, threadfunc, NULL);
checkResults("pthread_create()\n", rc);
printf("Wait for the thread to exit\n");
rc = pthread_join(thread, &status);

Check this simple C code I wrote for one of my libraries
/*
* Copyright (c) 2011 Dino Ciuffetti <dino#tuxweb.it>, TuxWeb S.r.l., NuvolaBase Ltd
*
* This file is part of liborient.
*
* Liborient is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Liborient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Liborient. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//pthread_rwlock_t ptr_thr_lock = PTHREAD_RWLOCK_INITIALIZER;
typedef struct {
int t;
} thread_arguments;
void *thread_stuff(void *args) {
thread_arguments *t_args;
int tid;
t_args = (thread_arguments *)args;
//pthread_rwlock_rdlock(&ptr_thr_lock);
tid = t_args->t;
//pthread_rwlock_unlock(&ptr_thr_lock);
/*while (1) {
sleep (1);*/
printf("Thread #%i!\n", tid);
/*}*/
t_args = NULL;
pthread_exit(NULL);
return NULL;
}
int wait_threads(pthread_t threads[], thread_arguments *t_args[], int nthreads) {
int t;
int rc;
// Waiting for threads termination
for(t=0; t<nthreads; t++) {
rc = pthread_join(threads[t], NULL);
free(t_args[t]);
if (rc != 0) {
printf("Error waiting for termination of thread %i: %i\n", t, rc);
return 1;
break;
}
}
return 0;
}
int spawn_threads(pthread_t threads[], thread_arguments *t_args[], int nthreads) {
int t;
int rc;
// Spawning threads
for(t=0; t<nthreads; t++) {
t_args[t] = (thread_arguments *) malloc(sizeof(thread_arguments));
//pthread_rwlock_wrlock(&ptr_thr_lock);
t_args[t]->t = t;
//pthread_rwlock_unlock(&ptr_thr_lock);
printf("Spawning thread: %i\n", t);
rc = pthread_create(&threads[t], NULL, (void *)thread_stuff, (void *)t_args[t]);
if (rc != 0) {
printf("Error spawning thread %i: %i\n", t, rc);
wait_threads(threads, t_args, rc+1);
return t+1;
break;
}
}
return 0;
}
int main() {
pthread_t threads[20];
thread_arguments *t_args[20];
int rc;
rc = spawn_threads(threads, t_args, 20);
if (rc > 0) {
printf("Failed spawning thread number %i\n", rc-1);
return 1;
}
rc = wait_threads(threads, t_args, 20);
return 0;
}

Related

pthread in C : i can't figure why pthread_cond_signal is not waking up one thread

I want a routine to be done by multiple threads, once they are created they need their work to be all finished before copying their calculated things. So a thread is on cond_wait once it has its work done.
A piece of code that works now:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_RAYCAST_THREADS 2
typedef struct s_thread_env
{
int id;
pthread_t thread;
int work_done;
void *shared_data;
} t_thread_env;
typedef struct s_shared_data
{
t_thread_env *tab_thread_env;
int max_thread;
int all_work_done;
pthread_mutex_t mutex;
pthread_cond_t cond;
int stop;
} t_shared_data;
void set_threads_again(int id, t_shared_data *shared_data)
{
int i;
shared_data->all_work_done = 0;
i = -1;
while (++i < shared_data->max_thread)
shared_data->tab_thread_env[i].work_done = 0;
//i = -1;
//while (++i < shared_data->max_thread)
//{
//if (i != id)
//{
//printf("cond_signal to thread %i\n", i);
//pthread_cond_signal(&shared_data->cond);
//}
//}
pthread_cond_broadcast(&shared_data->cond);
}
void wait_or_signal(t_thread_env *thread_env, t_shared_data *shared_data)
{
int i;
i = 0;
while (i < shared_data->max_thread && shared_data->tab_thread_env[i].work_done)
i++;
if (i == shared_data->max_thread)
{
printf(" allworkdone sent by thread %i\n", thread_env->id);
//printf(" copy_screenpixels() by thread %i\n", thread_env->id);
set_threads_again(thread_env->id, shared_data);
}
else
{
printf(" thread number %i is waiting for other threads\n", thread_env->id);
pthread_cond_wait(&shared_data->cond, &shared_data->mutex);
printf("ENFIN ! thread number %i woke up from condwait\n", thread_env->id);
}
}
void *routine(void *arg)
{
t_thread_env *thread_env;
t_shared_data *shared_data;
int stop;
thread_env = (t_thread_env *)arg;
shared_data = (t_shared_data *)thread_env->shared_data;
pthread_mutex_lock(&shared_data->mutex);
while (!shared_data->stop)
{
printf("new frame> thread_id = %i, thread_env->work_done = %i\n", thread_env->id, thread_env->work_done);
pthread_mutex_unlock(&shared_data->mutex);
printf(" raycast() in routine thread %i\n", thread_env->id);
pthread_mutex_lock(&shared_data->mutex);
thread_env->work_done++;
wait_or_signal(thread_env, shared_data);
}
pthread_mutex_unlock(&shared_data->mutex);
return (0);
}
void init_thread_env(t_shared_data *shared_data, int i)
{
t_thread_env *thread_env;
thread_env = &shared_data->tab_thread_env[i];
thread_env->id = i;
thread_env->shared_data = shared_data;
if (pthread_create(&thread_env->thread, NULL, routine, thread_env) != 0)
printf("Error pthread_create for %i\n", i);
}
void free_all(t_shared_data *shared_data)
{
int i;
pthread_mutex_lock(&shared_data->mutex);
shared_data->stop = 1;
pthread_mutex_unlock(&shared_data->mutex);
i = -1;
while (++i < shared_data->max_thread)
pthread_join(shared_data->tab_thread_env[i].thread, NULL);
printf("\nEND\n\n");
//free etc
}
int main()
{
int i;
t_shared_data *shared_data;
shared_data = (t_shared_data*)malloc(sizeof(t_shared_data)); // if (!shared data){free etc}
shared_data->max_thread = MAX_RAYCAST_THREADS;
pthread_mutex_init(&shared_data->mutex, 0);
pthread_cond_init(&shared_data->cond, 0);
shared_data->tab_thread_env = (t_thread_env*)malloc(sizeof(t_thread_env) * shared_data->max_thread);
i = -1;
while (++i < shared_data->max_thread)
init_thread_env(shared_data, i);
while (1)
sleep(1); //program is turning
free_all(shared_data);
return (0);
}
The correct output:
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
new frame> thread_id = 1, thread_env->work_done = 0
raycast() in routine thread 1
allworkdone sent by thread 1
cond_signal to thread 0
new frame> thread_id = 1, thread_env->work_done = 0
ENFIN ! thread number 0 woke up from condwait
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
raycast() in routine thread 1
allworkdone sent by thread 1
cond_signal to thread 0
new frame> thread_id = 1, thread_env->work_done = 0
ENFIN ! thread number 0 woke up from condwait
new frame> thread_id = 0, thread_env->work_done = 0
raycast() in routine thread 0
thread number 0 is waiting for other threads
raycast() in routine thread 1
Thank you for reading me, have a good day!
EDIT: I made a more readable and compilable version with only 1 mutex (old version: https://pastebin.com/4zMyBJi2).
EDIT2: deleted some parts of the original post, and tried to avoid every data races, my code still has some (as it still does not work). But I think I am close to get something working
EDIT3: Ok it is working now, I edited the code. The main issue was my disastrous use of the shared_data variables.
I tried to make my raycasting threads work using 1 call of
pthread_create for each thread (in an initialisation function). Is
it possible to do it?
Each successful call to pthread_create creates exactly one thread, so this is the only way to do it. But do not get confused between threads' start functions and threads themselves. Multiple threads can be created to run the same thread function, but this requires multiple calls to pthread_create, one for each thread.
I guess it is better (for performances) to do
it in this way (rather than an enormous amount of pthread_create and
pthread_join calls), is this correct?
Having chosen to use a certain number of threads to do certain pieces of work, the number of pthread_create calls is already determined. If you have performance concerns then they should be about how many threads to use, the details of the work they are to perform, and the nature and granularity of their synchronization.
In order to make it happen, the last thread (number n) to finish his
job has to tell the other ones that every thread has finished, so
there is a pthread_cond_wait for the (n - 1) first threads, and the
last thread (number n) calls pthread_cond_signal for each (n - 1)
first ones. Each thread has his own mutex.
That seems a little overkill, even if you can make it technically correct. It doesn't make much sense to have a mutex per thread, because mutexes are useful only when different threads use the same one. It may make sense to have different mutexes for protecting different shared resources, however. You would probably want CVs for some of those, but not all of them.
This appears to be (at least one area) where your code is failing. Your threads are not properly synchronized because they all rely on different mutexes to protect the same resources. It's not clear to me whether it makes sense for your program to have any more than just one mutex, but I would start by reducing your usage to that.

Losing my mind on a simple seg fault caused by pthread_create()

In this code, I'm trying to create an array of threads. I've set the pthreads value to 1. In the for loop, the address, ID, and "created" gets printed, but the function never seems to execute as I don't get a print.
The seg fault actually happens at pthread_join at the bottom, but it certainly has to be caused by the creation since the function never runs, right? producers[0] is the only thread since I'm just testing 1. The create function passes an (ID address, NULL, the void * function(), and void* arguments) like it's supposed to. It has to be something obvious but I've tried to figure it out for so long I'm empty.
typedef struct ThreadStruct {
int threadIndex;
} ThreadStruct;
void *producer(void* ts){
printf("in producer\n");
FILE* inputfp = threadstruct->inputFiles[0];
hostname = (char*)malloc((MAXNAME+1)*sizeof(char));
while(fscanf(inputfp, hostname) > 0){
printf("%s",hostname);
}
return 0;
}
int main(int argc, char *argv[]){
int pthreads = atoi(argv[1]); //always 1
ThreadStruct threadstruct;
pthread_t producers[pthreads];
for(int i=0;i<pthreads;i++){
printf("in pthread loop\n");
printf("%p \n",&producers[i]);
printf("%ld \n",producers[i]);
pthread_create(&producers[i], NULL, producer, (void *) &threadstruct);
}
pthread_join(producers[0], NULL);
}
Your code works in my side and would not produce the seg fault.
Here is the print out info:
$ ./pthread
in pthread loop
0xffffcb70
6444554784
in pthread loop
in producer
0xffffcb78
64
in pthread loop
in producer
0xffffcb80
1
in pthread loop
in producer
0xffffcb88
4299166064
in pthread loop
in producer
0xffffcb90
6443761969
in pthread loop
in producer
0xffffcb98
6445451520
in pthread loop
in producer
0xffffcba0
314761761601
in producer
exit main thread
Your code here:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
typedef struct ThreadStruct {
int threadIndex;
} ThreadStruct;
void *producer(void* ts){
printf("in producer\n");
return 0;
}
int main(int argc, char *argv[]){
int pthreads = 7;
ThreadStruct threadstruct;
pthread_t producers[pthreads];
for(int i=0;i<pthreads;i++){
printf("in pthread loop\n");
printf("%p \n",&producers[i]);
printf("%ld \n",producers[i]);
pthread_create(&producers[i], NULL, producer, (void *) &threadstruct);
}
pthread_join(producers[0], NULL);
printf("exit main thread\n");
}
you don't seem to check if the thread is actually created or not, in other words you don't seem to validate the return type of pthread_create and straight calling pthread_join probably leading to Undefined behavior, in case pthread_create fails.
pthread_create(&producers[i], NULL, producer, (void *) &threadstruct);
from pthread_join
The pthread_join() function shall fail if:
EINVAL The implementation has detected that the value specified by thread does not refer to a joinable thread.
ESRCH No thread could be found corresponding to that specified by the given thread ID.
however there are cases where pthread_join with invalid thread handle seg faults.
a piece of extract from the link above
"*Passing invalid handle to pthread_join is like passing invalid pointer to a system call.
The implementation may detect it and signal it in errno, but it may crash as
well.
There are 2 different POSIX threads implementations on Red Hat Linux
linuxthreads, where pthread_t handle is a small integer (and the number of
threads is substantially limited)
NPTL (the default, pthread_t is internally a pointer so that there are no
arbitrary thread limits)
You can request the old-fashioned threading library with LD_ASSUME_KERNEL=2.4.19
in the environment.
For NPTL where pthread_t is a pointer, pthread_join detects some invalid
handles where it can be done cheaply. But detecting all possible invalid
handles would be very costly (the implementation would basically have to take
a global lock and iterate over all currently running threads, comparing the
handle with each of them. With say 100000 running threads you can see how
costly it is).
This testcase works on SuSE since SuSE only ships the old-fashioned non-scalable
linuxthreads implementation.*"
from pthead_create
RETURN VALUE
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
perhaps something like this
if( pthread_create(&producers[i], NULL, producer, (void *) &threadstruct) ) {
perror("something wrong .. ");
exit(1);
}
Firstly check the return value of pthread_create() to check whether it was successful or not. For e.g
int ret = pthread_create(&producers[i], NULL, producer, (void *) &threadstruct);
if(ret) {
fprintf(stderr, "failed to create thread %s\n",strerror(ret));
exit(EXIT_FAILURE);
}
And Also it's advised to use pthread_join() for all the threads not only first thread, as if you want to wait for thread/s to terminate before further processing in main thread as mentioned here. Also check the return value of pthread_join().
Sample Code
#include<stdio.h>
#include<string.h>
#include<stdint.h>
#include<stdlib.h>
#include<pthread.h>
typedef struct ThreadStruct {
int threadIndex;
} ThreadStruct;
void *producer(void* ts){
printf("in producer\n");
return 0;
}
int main(int argc, char *argv[]){
int pthreads = 5;
int ret;
ThreadStruct threadstruct;
pthread_t producers[pthreads];
/* create threads */
for(intptr_t itr = 0;itr < pthreads; itr++){
printf("in pthread loop\n");
//printf("%p \n",&producers[itr]);
//printf("%ld \n",producers[itr]);
ret = pthread_create(&producers[itr], NULL, producer, (void *) &threadstruct);
if (ret) {
fprintf(stderr, "failed to create thread #%ld - %s\n",(long)itr, strerror(ret));
exit(EXIT_FAILURE);
}
}
/* join all threads */
for(intptr_t itr = 0; itr < pthreads; itr++){
printf("In main: joining thread #%ld\n", (long)itr);
ret = pthread_join(producers[itr], NULL);
if (ret) {
fprintf(stderr, "failed to join thread #%ld - %s\n",(long)itr, strerror(ret));
exit(EXIT_FAILURE);
}
}
//pthread_exit();
return 0;
}
it works in my system, hope it works for you also.

two threads, first adds second substracts

This is a classic example of mutex locks. I don't know why the following code doesn't work, ie. it doesn't print "ctr = 0" every time (but, for example, ctr = 535).
int ctr;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void * add (void * arg_wsk)
{
int i;
for (i = 0; i < 100000; i++) {
pthread_mutex_lock (&m);
ctr++;
pthread_mutex_unlock (&m);
}
return(NULL);
}
void * sub(void * arg_wsk)
{
int i;
for (i = 0; i < 100000; i++) {
pthread_mutex_lock (&m);
ctr--;
pthread_mutex_unlock (&m);
}
return(NULL);
}
int main()
{
pthread_t tid1, tid2;
int i;
void *res;
ctr = 0;
pthread_mutex_init(&m, NULL);
pthread_create(&tid1, NULL, add, NULL);
pthread_detach(tid1);
pthread_create(&tid2, NULL, sub, NULL);
pthread_detach(tid2);
pthread_join(tid1, &res);
pthread_join(tid2, &res);
pthread_mutex_destroy(&m);
printf("ctr = %d", ctr);
pthread_exit(NULL);
}
I think you are misusing the POSIX API. If you detach the threads, you shouldn't join them. Remove the detach and see if this improves things. I think you'll see that main() now blocks until the threads have completed.
Note also, from the link for the join call
ESRCH No thread could be found corresponding to that specified by the
given thread ID.
If you're lucky, you'll hit this. If you're not lucky, crazy things will happen. Don't mix detach and join calls on the same thread.
https://computing.llnl.gov/tutorials/pthreads/#Joining
The value of your counter ctr depends on both the threads completing their full execution.
According to pthread_detach(3)
Once a thread has been detached, it can't be joined with
pthread_join(3) or be made joinable again.
If you remove pthread_detach call from your program, you will get the expected output.
Also, consider explicitly creating your thread joinable(or detached) for portability.

printf with pthreads in C

I am working with pthreads right now doing the producer/consumer problem. I am currently just trying to get the producer working and using printf statements to see where my issues are. The problem is the code compiles just fine but when I run it, it doesn't do anything but seems to run just fine. I have tried setting my first line to a printf statement but even that does not print. I have tried using fflush as well and I am running out of ideas. My question why would even the first printf statement get skipped?
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
void *producer();
pthread_mutex_t lock;
pthread_cond_t done, full, empty;
int buffer[10];
int in = 0, out = 0;
int min = 0, max = 0, numOfItems = 0, total = 0;
double avg;
void *producer() {
srand(time(NULL));
int n = rand();
int i;
for(i = 0; i < n; i++)
{
int random = rand();
pthread_mutex_lock(&lock);
buffer[in++] = random;
if(in == 10)
{
pthread_cond_signal(&full);
printf("Buffer full");
pthread_mutex_unlock(&lock);
sleep(1);
}
}
pthread_exit(NULL);
}
void *consumer() {
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
printf("test");
//Create threads and attribute
pthread_t ptid, ctid;
pthread_attr_t attr;
//Initialize conditions and mutex
pthread_cond_init(&full, NULL);
pthread_cond_init(&empty, NULL);
pthread_cond_init(&done, NULL);
pthread_mutex_init(&lock, NULL);
//Create joinable state
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&ptid, &attr,(void *)producer,NULL);
pthread_create(&ctid, &attr,(void *)consumer,NULL);
pthread_join(ptid,NULL);
pthread_join(ctid,NULL);
printf("Program Finished!");
pthread_exit(NULL);
}
man pthread_mutex_init
pthread_mutex_init initializes the mutex object pointed to by mutex
according to the mutex attributes specified in mutexattr. If mutexattr
is NULL, default attributes are used instead.
The LinuxThreads implementation supports only one mutex attributes, the
mutex kind... The kind of a mutex determines whether it can be locked again by
a thread that already owns it. The default kind is fast...
If the mutex is already locked by the calling thread, the behavior of
pthread_mutex_lock depends on the kind of the mutex. If the mutex is of
the fast kind, the calling thread is suspended until the mutex is
unlocked, thus effectively causing the calling thread to deadlock.
That's what happens to your producer: it deadlocks in the call
pthread_mutex_lock(&lock);
- except in the unlikely case n < 2 - thus producing no output.

Unable to Find Segfault Cause

The program is supposed to create x amount of threads based on the arguments that are passed to it. argv[1] is the amount main is supposed to sleep, argv[2] is the number of propucer threads, and argv[3] is the number of consumer threads. The program compiles fine and the command I have been using to run it is: program 10 1 1.
I've been staring at this code for a while now and I can't seem to find what is causing the segmentation fault. Maybe a second set of eyes will be able to pick it quickly.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>
#include "buffer.h"
void *producer(void *);
void *consumer(void *);
// Semaphores
sem_t empty;
sem_t full;
pthread_mutex_t mutex;
// Buffer
int placed = 0;
buffer_item buffer[BUFFER_SIZE];
int insert_item(buffer_item item){
/* INSERT ITEM INTO BUFFER */
int z;
sem_wait(&empty);
//mutex lock
z = pthread_mutex_lock(&mutex);
if (z != 0){
return -1;
}
buffer[placed] = item;
//mutex unlock
z = pthread_mutex_unlock(&mutex);
if (z != 0){
return -1;
}
sem_post(&full);
placed++;
printf("producer produced %d\n", item);
}
int remove_item(buffer_item *item){
/* REMOVE ITEM FROM BUFFER */
int m;
placed--;
sem_wait(&full);
//mutex lock
m = pthread_mutex_lock(&mutex);
if (m != 0){
return -1;
}
buffer[placed] = -1;
//mutex unlock
m = pthread_mutex_unlock(&mutex);
if (m != 0){
return -1;
}
sem_post(&empty);
printf("consumer consumed %d\n", rand);
return 0;
}
// Main
int main(int argc, char *argv[]){
int sleepNum, pThreadNum, cThreadNum, p;
sleepNum = atoi(argv[1]);
pThreadNum = atoi(argv[2]);
cThreadNum = atoi(argv[3]);
// Initialize Semaphores & mutex
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
// Create producer thread
pthread_t tid[pThreadNum];
int g=pThreadNum-1;
while(g >= 0){
p = pthread_create(&tid[g], NULL, producer, NULL);
g--;
}
printf("created prod thread");
// Create consumer thread
pthread_t kid[cThreadNum];
g = cThreadNum-1;
while(g >= 0){
p = pthread_create(&kid[g], NULL, consumer, NULL);
g--;
}
// Sleep for argv[0]
sleep(sleepNum);
// Destroy mutex & semaphores
sem_destroy(&empty);
sem_destroy(&full);
p = pthread_mutex_destroy(&mutex);
// Exit
exit(0);
}
// Producer
void *producer(void *param){
buffer_item rand;
unsigned int *seed;
int b;
while(1){
sleep(2);
rand = rand_r(seed);
b = insert_item(rand);
if (b < 0){
printf("Error producing item.");
}
}
}
// Consumer
void *consumer(void *param){
buffer_item rand;
int d;
while(1){
sleep(2);
d = remove_item(&rand);
if (d < 0){
printf("Error removing item");
}
}
}
Thanks in advance!
On Unix, you can get the backtrace from a segmentation fault by dumping core and examing the corefile in gdb.
$ ulimit -c <max core file size in 1k blocks>
$ gdb program core
gdb> bt
should dump the backtrace, and you can see exactly which line segfaulted.
In the producer you are using an uninitialized pointer. Try allocating some memory for it using malloc. I'm not explaining exactly what it is because you tagged this as homework.
Also don't rely on the output from printf statements to tell you where the program got to when using threads. It helps if you flush the output stream explicitly after each printf, then you'll almost get an idea of the right sequence of events.
compile your program with -g, as gcc -g program.c -lpthread
then
gdb a.out
set breakpoint as
b main
start
and then use s for step by step execution and see where it is falling.
As someone already mentioned that your producer function has uninitialized pointer unsigned int *seed;
also this program has lost wake-up problem associated with it, along with normal unlocking problem ( as in function insert item, what if insert_item thread context-switched before doing placed++. )
Here's a great article for finding the causes of segfaults.
Link
Link mirrored here, in case it ever goes down.... you never know.

Resources