mutex

mutex word is shot form of mutual exclusion. In computer, mutex is a synchronization methood which prevent multiple threads from accessing the critical section(shared resource/shared block of code/shared memory etc).

lets look at this program.

here we are creating two threads and both threads are trying to write a common file same time without any synchronization.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#define FILE_TO_LOG "log.txt"

void *callback1(void *arg)
{
	int fd;
	int ret;
	
	fd = open(FILE_TO_LOG, O_WRONLY | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T1: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}

	ret = write(fd, "Hello\n", 6);
	if (ret <= 0) {
		fprintf(stderr, "T1: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T1: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);

	pthread_exit(NULL);
}

void *callback2(void *arg)
{
	int fd;
	int ret;
	
	fd = open(FILE_TO_LOG, O_WRONLY | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T2: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}

	ret = write(fd, "Hi\n", 3);
	if (ret <= 0) {
		fprintf(stderr, "T2: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T2: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);

	pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t tid1, tid2;

	unlink(FILE_TO_LOG);

	/* creating first thread */
	ret = pthread_create(&tid1, NULL, callback1, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 1\n");
		return -1;
	}
	
	/* creating second thread */
	ret = pthread_create(&tid2, NULL, callback2, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 2\n");
		pthread_join(tid1, NULL);
		return -1;
	}

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	return 0;
}

Now look at this program having same usecase with mutex synchronization

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#define FILE_TO_LOG "log.txt"

pthread_mutex_t lock;

void *callback1(void *arg)
{
	int fd;
	int ret;

	pthread_mutex_lock(&lock);	
	fd = open(FILE_TO_LOG, O_WRONLY | O_APPEND | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T1: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}

	ret = write(fd, "Hello\n", 6);
	if (ret <= 0) {
		fprintf(stderr, "T1: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T1: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);
	pthread_mutex_unlock(&lock);

	pthread_exit(NULL);
}

void *callback2(void *arg)
{
	int fd;
	int ret;

	pthread_mutex_lock(&lock);	
	fd = open(FILE_TO_LOG, O_WRONLY | O_APPEND | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T2: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}

	ret = write(fd, "Hi\n", 3);
	if (ret <= 0) {
		fprintf(stderr, "T2: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T2: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);
	pthread_mutex_unlock(&lock);

	pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t tid1, tid2;

	unlink(FILE_TO_LOG);

	ret = pthread_mutex_init(&lock, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to init mutex\n");
		return -1;
	}

	/* creating first thread */
	ret = pthread_create(&tid1, NULL, callback1, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 1\n");
		return -1;
	}
	
	/* creating second thread */
	ret = pthread_create(&tid2, NULL, callback2, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 2\n");
		pthread_join(tid1, NULL);
		return -1;
	}

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	return 0;
}

Now its working good as pre usecase, wait a min, still there are some critical isue the the above program. lets figure it out.

TODO

Conditional sync variables

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>

#define FILE_TO_LOG "log.txt"

pthread_mutex_t lock;
pthread_cond_t cond;

void *callback1(void *arg)
{
	int fd;
	int ret;

	pthread_mutex_lock(&lock);
	
	fd = open(FILE_TO_LOG, O_WRONLY | O_APPEND | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T1: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}
	
	ret = write(fd, "Hello\n", 6);
	if (ret <= 0) {
		fprintf(stderr, "T1: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T1: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);
	pthread_mutex_unlock(&lock);
	pthread_cond_signal(&cond);

	pthread_exit(NULL);
}

void *callback2(void *arg)
{
	int fd;
	int ret;

	pthread_mutex_lock(&lock);
	
	pthread_cond_wait(&cond, &lock);	
	
	fd = open(FILE_TO_LOG, O_WRONLY | O_APPEND | O_CREAT, 0666);
	if (fd < 0) {
		fprintf(stderr, "T2: failed to open %s file\n", FILE_TO_LOG);
		pthread_exit(NULL);
	}

	ret = write(fd, "Hi\n", 3);
	if (ret <= 0) {
		fprintf(stderr, "T2: failed to write %s file\n", FILE_TO_LOG);
	} else {
		printf("T2: %d byte written to %s\n", ret, FILE_TO_LOG);
	}

	close(fd);
	pthread_mutex_unlock(&lock);

	pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t tid1, tid2;

	unlink(FILE_TO_LOG);

	ret = pthread_mutex_init(&lock, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to init mutex\n");
		return -1;
	}
	ret = pthread_cond_init(&cond, 0);
	if (ret != 0) {
		fprintf(stderr, "failed to init condition\n");
		return -1;
	}

	/* creating first thread */
	ret = pthread_create(&tid1, NULL, callback1, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 1\n");
		return -1;
	}
	
	/* creating second thread */
	ret = pthread_create(&tid2, NULL, callback2, NULL);
	if (ret != 0) {
		fprintf(stderr, "failed to create thread 2\n");
		pthread_join(tid1, NULL);
		return -1;
	}

	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);
	return 0;
}

lets analyze above program.


©2023-2024 rculock.com