Thread by Example (4) : Thread Mutex

Mutex (MUTual EXclusion lock) memberikan solusi dari problem race condition saat beberapa thread berusaha mengakses kode secara bersamaan, sehingga hanya satu thread yang bisa mengaksesnya dalam satu waktu dan thread lain akan menunggu saat thread tersebut telah selesai mengaksesnya. Artinya jika satu thread telah mengunci mutex, dan thread berikutnya berusaha mengunci mutex, maka thread ini akan diblock atau pending, sampai thread pertama membuka kunci mutex.

Objective

Yang dipelajari:

  • inisialisasi mutex
  • lock dan unlock mutex

Fungsi yang digunakan

Fungsi yang digunakan untuk inisialisasi, mengunci, dan membuka kunci adalah:

  • int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) .
    Set atribut attr mutex, atau NULL untuk menggunakan attribut default. Deklarasi untuk inisialisasi mutex menggunakan attribut default adalah
  • pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, NULL);
    

    atau

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /*tidak memerlukan pthread_mutex_init*/
    
  • int pthread_mutex_lock(pthread_mutex_t *mutex)
    Kunci mutex. Jika mutex telah dilock, maka fungsi ini akan memblok eksekusi sampai mutex diunlock. Beberapa thread dapat sekaligus terblok oleh lock mutex, dan hanya satu thread yang unblock (secara acak) saat mutex diunlock.
  • int pthread_mutex_unlock(pthread_mutex_t *mutex)
    Membuka kunci mutex (unlock). Fungsi ini sebaiknya dipanggil oleh thread yang melock mutex.

Kode program

Berikut contoh kode yang menggunakan mutex dan semaphore sekaligus. Penjelasan ada di listing.

/* Belajar #4: job_mutex.c
* 
* Sistem antrian job dan processing
* 
* Compile dengan:
*    gcc -o job_mutex job_mutex.c -lpthread
*
* Objective:
* 1) inisialisasi mutex
* 2) lock dan unlock mutex
* 
* Code listing from "Advanced Linux Programming," by CodeSourcery LLC
*/

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

struct job_desc {
   char *desc;
   int delayed; /*delayed time before job processed*/
};

struct job {
  /* Link field for linked list.  */
  struct job* next; 
  /* Other fields describing work to be done... */
  struct job_desc* desc;
};


/* A linked list of pending jobs.  */
struct job* job_queue;

/* Prototype */
void process_job (struct job* jobs);
void enqueue_job(struct job_desc* jobs_desc);
void* thread_function (void* arg);
void initialize_job_queue ();

/* A mutex protecting job_queue.  */
pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;

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

/* Main program */
int main()
{
  pthread_t thread_id;
  int i;
  struct job_desc desc[4] = {{"Job #1",2},
	{"Job #2",3},
	{"Job #3",1},
	{"Job #4",4},		
  };

  /* Init job_queue*/
  initialize_job_queue();

  /* Create a thread*/
  pthread_create(&thread_id, NULL, &thread_function, NULL);

  /* Add 4 jobs to queue*/
  printf("Jobs list: \n");
  for (i=0; i<4; i++) {
	printf("jobs=%s, delayed=%d\n", desc[i].desc, desc[i].delayed);
	enqueue_job (&desc[i]); /*add job_desc*/		
  }
  printf("\n");

  /* Wait thread finished*/
  pthread_join(thread_id, NULL);

  return 0;	
}

/* Process the jobs
*/
void process_job (struct job* jobs)
{
  sleep(jobs->desc->delayed); /*each job has process time*/
  printf("%s has been processed with delay=%d\n", jobs->desc->desc, jobs->desc->delayed);
}

/* Perform one-time initialization of the job queue.  */
void initialize_job_queue ()
{
  /* The queue is initially empty.  */
  job_queue = NULL;
  /* Initialize the semaphore which counts jobs in the queue.  Its
     initial value should be zero.  */
  sem_init (&job_queue_count, 0, 0);
}

/* Process queued jobs until the queue is empty.  */

void* thread_function (void* arg)
{

  printf("Thread has been called.\n");	
  while (1) {
    struct job* next_job;
    struct job* waiting_job;

    /* Wait on the job queue semaphore.  If its value is positive,
      indicating that the queue is not empty, decrement the count by
      one.  If the queue is empty, block until a new job is enqueued.  */

    if (job_queue != NULL ) { /*there is a jobs*/
   	waiting_job = job_queue->next;   
   	while ( waiting_job != NULL ) {
   		printf("%s ",waiting_job->desc->desc);
   		waiting_job = waiting_job->next;    	
   	}
    	printf(" :waiting\n");
    }	
    sem_wait (&job_queue_count);

    /* Lock the mutex on the job queue.  */
    pthread_mutex_lock (&job_queue_mutex);
    /* Because of the semaphore, we know the queue is not empty.  Get
      the next available job.  */
    next_job = job_queue;
    /* Remove this job from the list.  */
    job_queue = job_queue->next;

    /* Carry out the work.  */
    process_job (next_job);

    /* Unlock the mutex on the job queue, since we're done with the
      queue for now.  */
    pthread_mutex_unlock (&job_queue_mutex);

    /* Clean up.  */
    free (next_job);
  }
  return NULL;
}

/* Add a new job to the front of the job queue.  */

void enqueue_job (struct job_desc* jobs_desc)
{
  struct job* new_job;

  /* Allocate a new job object.  */
  new_job = (struct job*) malloc (sizeof (struct job));
  /* Set the other fields of the job struct here...  */

  /* Lock the mutex on the job queue before accessing it.  */
  pthread_mutex_lock (&job_queue_mutex);
  /* Place the new job at the head of the queue.  */
  new_job->next = job_queue;
  new_job->desc = jobs_desc;
  job_queue = new_job;

  /* Post to the semaphore to indicate another job is available.  If
    threads are blocked, waiting on the semaphore, one will become
    unblocked so it can process the job.  */
  sem_post (&job_queue_count);

  /* Unlock the job queue mutex.  */
  pthread_mutex_unlock (&job_queue_mutex);
}

Referensi

One Comment to “Thread by Example (4) : Thread Mutex”

  1. Good day! I just would like to give an enormous thumbs up for
    the great info you will have right here on this post.
    I can be coming again to your weblog for extra soon.

Tinggalkan Balasan

Isikan data di bawah atau klik salah satu ikon untuk log in:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: