简体   繁体   中英

Semaphore doesn't seem to work correctly with multiple threads

I try to write multiple threading example with C. Which is the gets number from user and sum numbers in two thread.

Threads are directly away each other, front to back and back to front.

I am using semaphore to manage global variables but output shows that semaphore do not work correctly.

What is wrong?

Output of code:

Array size? :10
Array of contents? :4 2 8 1 5 3 7 9 6 10
Thread_1 > read 4, sum is = 4 
Thread_1 > read 2, sum is = 6 
Thread_1 > read 8, sum is = 14 
Thread_1 > read 1, sum is = 15 
Thread_1 > read 5, sum is = 20 
Thread_1 > read 3, sum is = 23 
Thread_1 > read 7, sum is = 30 
Thread_1 > read 9, sum is = 39 
Thread_1 > read 6, sum is = 45 
Thread_1 > read 10, sum is = 55 
Thread_1 > End. 
Thread_2 > End. 

Code :

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

int *array; //Global integer array
int sum;    //Global sum variable
int counter = 0;

sem_t mutex;

void *front_to_back( void *val )
{
  int SIZE;
  SIZE = *((int *) val);

  while (1)
  {
    sem_wait(&mutex);

    if( counter != SIZE )
    {
      sum = sum + array[counter];

      printf("Thread_1 > read %d, sum is = %d \n", array[counter], sum);

      counter++;

    }else
    {
      printf("Thread_1 > End. \n");

      sem_post(&mutex);

      break;
    }

    sem_post(&mutex);
  }
}


void *back_to_front( void *val )
{
  int SIZE;
  SIZE = *((int *) val);

  int i=1;

  while (1)
  {
    sem_wait(&mutex);

    if( counter != SIZE )
    {
      sum = sum + array[SIZE - i];

      printf("Thread_2 > read %d, sum is = %d \n", array[SIZE - i], sum);

      counter++;
      i++;

    }else
    {
      printf("Thread_2 > End. \n");

      sem_post(&mutex);

      break;
    }

    sem_post(&mutex);
  }
}

main(){

  int SIZE;

  printf("Array size? :");
  scanf("%d", &SIZE);

  array = malloc(SIZE*sizeof(int));

  int i=0;

  printf("Array of contents? :");
  for (i ; i<SIZE ; i++)
  {
    scanf("%d", &array[i]);
  }

  pthread_t t[2];

  sem_init(&mutex, 0, 1);

  pthread_create(&t[1], NULL, front_to_back, (void *) &SIZE );
  pthread_create(&t[2], NULL, back_to_front, (void *) &SIZE );

  pthread_join(t[1],NULL);
  pthread_join(t[2],NULL);

  free(array);
  sem_destroy(&mutex);

}

You should be using t[0] and t[1] in main() : an array of size N has valid indexes in 0..N-1 , so, first, fix that. Here's the correct code:

pthread_create(&t[0], NULL, front_to_back, (void *) &SIZE );
pthread_create(&t[1], NULL, back_to_front, (void *) &SIZE );

pthread_join(t[0],NULL);
pthread_join(t[1],NULL);

Ideally, you should also check if malloc() and pthread_create() succeed. These functions can return with an error, and you should handle it. Your code ignores the errors (with the out-of-bounds access, you are actually lucky that it worked at all).

Also, why are you using a semaphore as if it were a mutex? A semaphore is not really needed here - when you don't need the power and flexibility of a semaphore, just use a mutex. One important difference is that semaphores allow you to wait on one thread and post on another, whereas a mutex must be unlocked by the thread that acquires it.

Thus, using a semaphore where a mutex would be enough may be covering up an error in your code. So, I'd go ahead and use a mutex instead. Here's the code with all of the changes:

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

int *array; //Global integer array
int sum;    //Global sum variable
int counter = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *front_to_back( void *val )
{
    int SIZE;
    SIZE = *((int *) val);

    while (1)
    {
        pthread_mutex_lock(&mutex);

        if( counter != SIZE )
        {
            sum = sum + array[counter];

            printf("Thread_1 > read %d, sum is = %d \n", array[counter], sum);

            counter++;

        }else
        {
            printf("Thread_1 > End. \n");

            pthread_mutex_unlock(&mutex);

            break;
        }

        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}


void *back_to_front( void *val )
{
    int SIZE;
    SIZE = *((int *) val);

    int i=1;

    while (1)
    {
        pthread_mutex_lock(&mutex);

        if( counter != SIZE )
        {
            sum = sum + array[SIZE - i];

            printf("Thread_2 > read %d, sum is = %d \n", array[SIZE - i], sum);

            counter++;
            i++;

        }else
        {
            printf("Thread_2 > End. \n");

            pthread_mutex_unlock(&mutex);

            break;
        }

        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main(void) {

    int SIZE;

    printf("Array size? :");
    scanf("%d", &SIZE);

    array = malloc(SIZE*sizeof(int));

    int i=0;

    printf("Array of contents? :");
    for (; i<SIZE ; i++)
    {
        scanf("%d", &array[i]);
    }

    pthread_t t[2];

    pthread_create(&t[0], NULL, front_to_back, (void *) &SIZE );
    pthread_create(&t[1], NULL, back_to_front, (void *) &SIZE );

    pthread_join(t[0],NULL);
    pthread_join(t[1],NULL);

    free(array);

    return 0;

}

I don't see any other problems with the code at first sight.

Now, it seems like your problem is that you're not seeing any parallelism. You should try with a bigger array. A single thread is probably able to process a 10-element array before context switching.

UPDATE : I just tried the code with a 3000-element array. You can clearly see them executing in parallel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM