0
votes

initially when I have only one sem_t *queue inside the struct, when I initialize it, the programs run without any errors and problems.

 #include <semaphore.h>

 typedef struct barrier {
   int count;
   sem_t *queue;
} barrier_t;

void barrier_init ( barrier_t *barrier, int count );

#include "barrier.h"
#include <stdlib.h>

// Initialise barrier here
void barrier_init ( barrier_t *barrier, int count ) 
{

  barrier->count = count;
  barrier->queue = malloc(sizeof(sem_t));
  sem_init(barrier->queue, 0, 0);

 }

however, when I have two sem_t in struct barrier when I initialize and run with Valgrind, it signals to me that there is an invalid write of size 8, even though the program runs and outputs normally.

#include "barrier.h"
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
typedef struct barrier {
  int count;
  sem_t *queue, *mutex;
}  barrier_t;

void barrier_init ( barrier_t *barrier, int count ) 
{
 
  barrier->count = count;
  barrier->queue = malloc(sizeof(sem_t));
  barrier->mutex = malloc(sizeof(sem_t));
  sem_init(barrier->mutex, 0, 1);
  sem_init(barrier->queue, 0, 0);

}
void barrier_wait ( barrier_t *barrier ) 
{   
  sem_wait(barrier->mutex);
  barrier->count--;
  sem_post(barrier->mutex);

  if (barrier->count == 0) {      
    sem_post(barrier->queue);    
  }



  sem_wait(barrier->queue);
  sem_post(barrier->queue);
}

// Perform cleanup here if you need to
void barrier_destroy ( barrier_t *barrier ) 
{

  sem_destroy(barrier->queue);
  sem_destroy(barrier->mutex);
  free(barrier->queue);
  free(barrier->mutex);   
}

The main function was a template given which should not have any issues. Valgrind has no issue with memory leaks as well only errors indicating invalid write and read of size 8. so here's the main function:

#include <pthread.h>
#include <semaphore.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "barrier.h"

sem_t *common_sem;
int waiting_at_barrier = 0;

typedef struct thread_task {
  int       thread_id;
  barrier_t *barrier;
  int       thread_return;
  int       sleep_time;
} thread_task_t;


void* run_thread( void* task ) 
{
  thread_task_t* thread_task = (thread_task_t*) task;
  const int thread_id = thread_task->thread_id;
  barrier_t *barrier = thread_task->barrier;

  usleep( thread_task->sleep_time );

  sem_wait( common_sem );
  waiting_at_barrier++;
  sem_post( common_sem );

  printf ( "[Thread %2d] waiting on barrier\n", thread_id );
  barrier_wait( barrier );
  printf ( "[Thread %2d] exiting barrier\n", thread_id );
  thread_task->thread_return = waiting_at_barrier;

  pthread_exit(0);
  }

int main ( int argc, char *argv[] ) 
{

  if (argc < 2) {
  printf("usage: %s threads [seed]\n", argv[0]);
  exit(1);
  }

  if (argc > 2) {
    srand(atoi(argv[2])); // [atoi] defaults to 0 if cannot be parsed.
  }

  const int total_threads = argc > 1 ? atoi(argv[1]) : 50;
  // initialise common semaphore
  common_sem = malloc(sizeof(sem_t));
  sem_init( common_sem, 0, 1 );


  barrier_t *barrier = malloc( sizeof(barrier_t) );
  barrier_init( barrier, total_threads );

  pthread_t threads[total_threads];
  thread_task_t *thread_tasks = malloc(sizeof(thread_task_t) * 
  total_threads);

  int i;
  for (i = 0; i < total_threads; i++) {
    thread_tasks[i].thread_id = i;
    thread_tasks[i].barrier = barrier;
    thread_tasks[i].sleep_time = (rand() % 500) * 1000;
    pthread_create( &threads[i], NULL, run_thread, (void*) 
    &thread_tasks[i] );
  }

  // wait and collect the tasks
  bool error_found = false;
  for (i = 0; i < total_threads; i++) {
    pthread_join( threads[i], NULL );
    if (thread_tasks[i].thread_return < total_threads) {
    error_found = true;
    printf ( "[Thread %2d] exited with %d other tasks (expected: 
      %d)\n",i,thread_tasks[i].thread_return,
           total_threads );
    }
  }

  free(thread_tasks);

  barrier_destroy(barrier);
  free(barrier);

  sem_destroy( common_sem );
  free( common_sem );

  if (error_found) {
    printf ( "Incorrect executions found\n" );
    exit(1);
  }
  return 0;
  }

THis is part of the Valgrind errors:

Invalid write of size 8 at 0x1098BB: barrier_init (in /home/hzxin/work/2106/lab3/L3/ex1/ex1) by 0x10948F: main (in /home/hzxin/work/2106/lab3/L3/ex1/ex1) Address 0x4a730b0 is 0 bytes after a block of size 16 alloc'dat 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)

1
Please show main. Please add relevant #includes. Please create a full minimal reproducible example. The problem might be that barrier is invalid pointer.KamilCuk
@KamilCuk have updated the MainHzxin
what are your compilation and valgrind calls?Eben
@Eben There is a Makefile given in the template the content of the Makefile is as follow: CC=gcc CFLAGS=-Wall LDLIBS=-lpthread .PHONY: clean ex1: barrier.o ex1.o barrier.o: barrier.c barrier.h clean: rm barrier.o ex1.o ex1 .PHONY: all all: ex1Hzxin
Yes, that Makefile just compiles it and links against pthread libraryEben

1 Answers

1
votes

I added a small main function and also a simple deinit function. Compiling with gcc 9.3.0 and checking with valgrind 3.15 yields no problem. Double check how you are calling your functions.

Running your updated code in Valgrind works just fine for me.