Hi! I'm trying to emplement the job queue. Somehow i can't initialize it: the queue is empty

Inline Code Example Here //INCLUDES

include <stdio.h>
include <stdlib.h>
include <semaphore.h>
include <pthread.h>

//GLOBALS
pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
int i;

define N_threads 10

int val=0;
//STRUCTURES
typedef struct job
{
int data;

struct job *next;
}job_t;

// A linked list of jobs.
job_t *job_queue=NULL;

// A semaphore counting the number of jobs in the queue.
sem_t job_queue_count;

//FUNCTION'S DECLARATION
int init_job_queue(job_t **head,job_t **tail);//initialize the queue
int add_node_to_head(job_t head);//add job to queue
void remove_node_from_tail(job_t **head);//remove job from queue in FIFO order
int process_job(job_t *the_job);//thread function itself
void
thread_func(void* arg);
int main()
{
pthread_t thr_id[N_threads];//array of thread id's
int i=0;
int status=-1;
job_t (head)=NULL;
job_t (
tail)=NULL;
sem_init(&job_queue_count,0,1);//initializing semaphore, 1 token is available
status= init_job_queue(&head,&tail);
if(status==-1)
{
printf("Error in memory allocation\n");
return -1;
}

for(i=0;i<N_threads;i++)
{
pthread_create(&thr_id[i],NULL,thread_func,NULL);
}
for(i=0;i<N_threads;i++)
{
pthread_join(thr_id[i],NULL);
}
printf("MAIN:all threads have been terminated\n");
return 0;
}

void* thread_func(void* arg)
{
job_t* current_job = NULL;
printf("THREAD FUNC: thread_id = 0x%x job_queue=0x%d \n", pthread_self(),job_queue);
for(;;)
{
sem_wait(&job_queue_count);
pthread_mutex_lock (&job_queue_mutex);
//safe
if (job_queue == NULL)
{

  current_job = NULL;
printf("There is nothing to do. Sorry\n");
}
else
{
  //taking the job
  current_job = job_queue;
  job_queue = job_queue->next;//remooving the job from the job queue
}

pthread_mutex_unlock (&job_queue_mutex);
sem_post(&job_queue_count);

//in case that queue was empty:
if (current_job == NULL)
break;

//processing the job
process_job (current_job);
free (current_job);
}

return NULL;
}

//functions definition
int init_job_queue(job_t **head,job_t **tail)
{
int flag=-1;
int i;
i=0;
head=(job_t)malloc(sizeof(job_t));
(head)->next =NULL;
(
head)->data = 0;
for(i=0;i<N_threads;i++)
{
flag=add_node_to_head(&head);
if(flag==-1)
{
printf("Error in memory allocation.\n");
return -1;
}
}
return 0;
}

int add_node_to_head(job_t** head)
{
job_t* temp=NULL;
temp=(job_t*)malloc(sizeof(job_t));
if(temp==NULL)
{
printf("Error in memory allocation.\n");
return -1;
}

temp->next=head;
temp->data=val+1;
*head=temp;
sem_post (&amp;job_queue_count);
return 0;
}
void remove_node_from_tail(job_t** head)
{
job_t *p1=
head;
job_t p2=p1->next;
while(p2->next!=0)
{
p1=p1->next;
p2=p2->next;
}
p1->next=NULL;
free(p2);
return;
}
int process_job(job_t
the_job)
{
printf("JOB NUMBER :%d process_job() thread_id=0x%d the_job=0x%d data = %d\n",i,pthread_self(),the_job,the_job->data);

return 0;
}

Help,please.....

Dani AI

Generated

A short diagnosis and concise fixes tied to the thread above.

The root cause was not a mysterious runtime bug but a mix of pointer/initialization mistakes plus incorrect semaphore usage. initialized the queue and semaphore in ways that left the list unreachable; correctly spotted pointer-to-pointer errors and the Mac/sem difference and got the program to run. To make the queue robust and portable, apply the fixes below.

Key fixes and rationale

  • Fix init: assign into the caller’s pointer (*head = malloc(...)) and set (*head)->next = NULL. Make sure the global job_queue and the local head you pass around refer to the same list (or stop passing head and use the single global consistently).
  • Use the semaphore as a job counter, not as a replacement mutex. If the queue starts empty initialize the semaphore to 0. Producers do sem_post() after appending a node; consumers do sem_wait() to block until a job exists, then lock the mutex, pop the node, unlock, process it, and free it. Do not sem_post() in the consumer after removing a job.
  • Keep the mutex strictly around list manipulation only. Incrementing val or modifying shared counters should happen under that same mutex (or use atomics). Prefer appending at the tail to preserve FIFO semantics.
  • API and diagnostics: declare the worker as void *thread_func(void*) and make process_job accept job_t*. Use %p to print pointers and cast pthread_self() for portable printing (e.g., (unsigned long)pthread_self() with %lu). Always check return values from malloc, pthread_*, and sem_* calls.

Shutdown and cleanup

Use a clean shutdown method: either push N sentinel jobs (one per worker) or set a shutdown flag and sem_post() once per thread to unblock them, then pthread_join() and destroy mutexes/semaphores. Finally free any leftover nodes.

These changes address the pointer initialization and semaphore semantics that made the queue appear empty and will make the worker pool predictable and safe.

Not really sure what you want this program to do. I had to change the sem_init to sem_open because I have a Mac (should change the functionality). I didn't check anything else like memory leaks, so see if this helps. Jobs are added to the queue and each thread processes one job then exits. If you leave the for(;;) loop in the threads, the first thread will most likely process all of the jobs on the queue and the other threads will do nothing. That is why I took it out, if that is what you want then put it back in. I also remove the sem_post in the add_node_to_head, I didn't think you wanted them or needed them. You problem was pointers to pointers and when to de-reference them in functions so you effect the value in the calling function.

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>

//GLOBALS
pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;
int i;

#define N_threads 10
int val=0;

//STRUCTURES
typedef struct job
{
  int data;
  struct job *next;
} job_t;

// A linked list of jobs.
job_t *job_queue=NULL;

// A semaphore counting the number of jobs in the queue.
sem_t *job_queue_count=NULL;

//FUNCTION'S DECLARATION
int init_job_queue(job_t **head,job_t **tail);//initialize the queue
int add_node_to_head(job_t **head);//add job to queue
void remove_node_from_tail(job_t **head);//remove job from queue in FIFO order
int process_job(job_t *the_job);//thread function itself
void *thread_func(void* arg);

int main()
{
  pthread_t thr_id[N_threads];//array of thread id's
  int i=0;
  int status=-1;
  job_t *head=NULL;
  job_t *tail=NULL;

  //sem_init(&job_queue_count,0,1);//initializing semaphore, 1 token is available
  job_queue_count=sem_open("/mySem",O_CREAT,S_IRUSR | S_IWUSR,1);
  if ( job_queue_count == SEM_FAILED ) {
    printf("%s\n",strerror(errno));
    return 0;
  }
  status= init_job_queue(&job_queue,&tail);

  if(status==-1) {
     printf("Error in memory allocation\n");
     return -1;
  }

  for(i=0;i<N_threads;i++) {
    pthread_create(&thr_id[i],NULL,(void *(*)(void *))thread_func,NULL);
  }
  for(i=0;i<N_threads;i++) {
     pthread_join(thr_id[i],NULL);
  }  
  sem_close(job_queue_count);
  sem_unlink("/mySem");
  printf("MAIN:all threads have been terminated\n");
  return 0;
}

void* thread_func(void* arg)
{
  job_t* current_job = NULL;
  printf("THREAD FUNC: thread_id = 0x%llx job_queue=%p \n", (unsigned long long)pthread_self(),job_queue);
  //for(;;)
  {
    if ( sem_wait(job_queue_count) == -1 ){
      printf("Error:  %s\n",strerror(errno));
    }
     pthread_mutex_lock (&job_queue_mutex);
     //safe
     if (job_queue == NULL)
     {
        current_job = NULL;
        printf("There is nothing to do. Sorry\n");
     }
     else
     {
        //taking the job
        current_job = job_queue;
        job_queue = job_queue->next;//remooving the job from the job queue
     }
     pthread_mutex_unlock (&job_queue_mutex);
     sem_post(job_queue_count);
     //in case that queue was empty:
     //if (current_job == NULL)
     //  break;

     //processing the job
     process_job (current_job);
     free (current_job);
  }

  return NULL;
}

//functions definition
int init_job_queue(job_t **head,job_t **tail)
{
  int flag=-1;
  int i;
  i=0;
  *head=(job_t *)malloc(sizeof(job_t));
  (*head)->next =NULL;
  (*head)->data = 0;
  for(i=0;i<N_threads;i++)
  {
     flag=add_node_to_head(head);
     if(flag==-1)
     {
        printf("Error in memory allocation.\n");
        return -1;
     }
  }
  return 0;
}

int add_node_to_head(job_t** head)
{
  job_t* temp=NULL;
  temp=(job_t*)malloc(sizeof(job_t));
  if(temp==NULL)
  {
    printf("Error in memory allocation.\n");
    return -1;
  }

  temp->next=*head;
  temp->data=val++;
  *head=temp;
  //sem_post (job_queue_count);
  return 0;
}
void remove_node_from_tail(job_t** head)
{
  job_t *p1=*head;
  job_t *p2=p1->next;
  while(p2->next!=0) {
    p1=p1->next;
    p2=p2->next;
  }
  p1->next=NULL;
  free(p2);
  return;
}

int process_job(job_t *the_job)
{
    printf("JOB NUMBER :%d process_job() thread_id=0x%llx "
           "the_job=%p data = %d\n",i++,
            (unsigned long long)pthread_self(), the_job,the_job->data);

  return 0;
}
Ouput
$ ./a.out
THREAD FUNC: thread_id = 0x1000b6000 job_queue=0x100100120 
JOB NUMBER :0 process_job() thread_id=0x1000b6000 the_job=0x100100120 data = 9
THREAD FUNC: thread_id = 0x100281000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x100304000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x100510000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x100387000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x100593000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x100616000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x10040a000 job_queue=0x100100110 
JOB NUMBER :1 process_job() thread_id=0x100281000 the_job=0x100100110 data = 8
THREAD FUNC: thread_id = 0x100699000 job_queue=0x100100110 
THREAD FUNC: thread_id = 0x10048d000 job_queue=0x100100110 
JOB NUMBER :2 process_job() thread_id=0x100304000 the_job=0x100100100 data = 7
JOB NUMBER :3 process_job() thread_id=0x100510000 the_job=0x1001000f0 data = 6
JOB NUMBER :4 process_job() thread_id=0x100387000 the_job=0x1001000e0 data = 5
JOB NUMBER :5 process_job() thread_id=0x100593000 the_job=0x1001000d0 data = 4
JOB NUMBER :6 process_job() thread_id=0x100616000 the_job=0x1001000c0 data = 3
JOB NUMBER :7 process_job() thread_id=0x10040a000 the_job=0x1001000b0 data = 2
JOB NUMBER :8 process_job() thread_id=0x100699000 the_job=0x1001000a0 data = 1
JOB NUMBER :9 process_job() thread_id=0x10048d000 the_job=0x100100090 data = 0
$
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.