Multithread Programming Based on Linux Programming (3)

Keywords: less Linux

Above, we briefly talked about the application of mutex in multi-threaded synchronization. In this paper, we briefly talked about the application of semaphores in multi-threaded synchronization. First of all, we will briefly talk about the basic concepts and operations of semaphore synchronization between multi-threads, and then write a small example to test it.

Basic concepts and operations of semaphores

The semaphore is essentially a non-negative integer counter, which is used to control access to public resources. Here is a brief review of the operation principle of the PV atom. PV atomic operation is the operation of integer counter sem. One P operation subtracts one SEM and one V operation adds one sem. Processes (or threads) determine whether they have access to public resources based on semaphore values. When the semaphore SEM is greater than or equal to zero, the process (or thread) has access to public resources; conversely, when the semaphore SEM is less than zero, the process (or thread) will block until the semaphore SEM The value is greater than or equal to zero.

Linux implements the anonymous semaphore of POSIX, which is mainly used for mutual exclusion and synchronization between threads. Here are some common functions.

a. Signal initialization function

int sem_init(sem_t *sem,int pshared,unsigned int value)
sem: Identification of the semaphore to be initialized

pshared: Decides that semaphores can be shared between several processes if used only in this process, set to 0
Value: semaphore initialization value

Return value: 0 success, other errors

b. Common functions of other semaphores

int sem_wait(sem_t *sem)	// Wait for a semaphore to continue until there is a semaphore
int sem_trywait(sem_t *sem)	// Wait for a semaphore and return immediately, whether or not
int sem_post(sem_t *sem)	// Sending semaphore
int sem_getvalue(sem_t *sem)	// Values used to obtain semaphores
int sem_destroy(sem_t *sem)	// Destroy a semaphore
sem: Identification of semaphores to be operated on

Return value: 0 success, other errors


II. Testing

Write a small test example to realize the function: Write three sub-threads, according to the parameters of the main thread to determine how many of the three sub-threads can run at the same time, the complete code is as follows:

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

/* Define a global variable for a semaphore */
static sem_t sem;

/*
 *	Thread body of sub-thread a
 */
static void *start_routine_a (void *arg)
{
	int loop_cnt = (int)arg;
	int i;

	sem_wait(&sem);		// Waiting semaphore

	printf("thread A : start!\n");

	for(i = 0; i < 5; i++)
	{
		printf("TECH-PRO thread A : %d\n", i);
		sleep(1);
	}

	printf("thread A : stop!\n");

	sem_post(&sem);		// Sending semaphore

	pthread_exit(NULL);		/* Thread Execution Completed */
}

/*
 *	Thread body of sub-thread b
 */
static void *start_routine_b (void *arg)
{
	int loop_cnt = (int)arg;
	int i;

	sem_wait(&sem);		// Waiting semaphore

	printf("thread B : start!\n");

	for(i = 0; i < 5; i++)
	{
		printf("TECH-PRO thread B : %d\n", i);
		sleep(1);
	}

	printf("thread B : stop!\n");

	sem_post(&sem);		// Sending semaphore

	pthread_exit(NULL);		/* Thread Execution Completed */
}

/*
 *	Thread body of subthread c
 */
static void *start_routine_c (void *arg)
{
	int loop_cnt = (int)arg;
	int i;

	sem_wait(&sem);		// Waiting semaphore

	printf("thread C : start!\n");

	for(i = 0; i < 5; i++)
	{
		printf("TECH-PRO thread C : %d\n", i);
		sleep(1);
	}

	printf("thread C : stop!\n");

	sem_post(&sem);		// Sending semaphore

	pthread_exit(NULL);		/* Thread Execution Completed */
}


/*
 *	Define three sub-threads and decide to run several threads in three threads at the same time based on the value passed in
 *	usage : pthread <1|2|3>
 */
int main(int argc, char *argv[])
{
	int ret;
	int value;
	pthread_t pthread_a, pthread_b, pthread_c;

	if(2 != argc)
	{
		printf("usage : %s <1|2|3>\n", argv[0]);
		return -1;
	}

	/* Get this value from the incoming parameters */
	value = strtoul(argv[1], NULL, 0);
	if((value < 1) || (value > 3))
	{
		printf("the value is out of boundary!\n");
		return -1;
	}

	/* Initialization semaphore */
	ret = sem_init(&sem, 0, value);
	if(0 != ret)
	{
		printf("sem_init error!\n");
		return -1;
	}

	/* start */
	printf("main : start!\n");

	/* Create two sub-threads */
	ret = pthread_create(&pthread_a, NULL, start_routine_a, (void *)5);
	if(0 != ret)
	{
		printf("pthread_create for a is failed!\n");
		return -1;
	}

	ret = pthread_create(&pthread_b, NULL, start_routine_b, (void *)5);
	if(0 != ret)
	{
		printf("pthread_create for b is failed!\n");
		return -1;
	}

	ret = pthread_create(&pthread_c, NULL, start_routine_c, (void *)5);
	if(0 != ret)
	{
		printf("pthread_create for c is failed!\n");
		return -1;
	}

	/* Waiting for the process to end */
	pthread_join(pthread_a, NULL);
	pthread_join(pthread_b, NULL);
	pthread_join(pthread_c, NULL);

	/* End */
	printf("main : stop!\n");

	sem_destroy(&sem);	// Destruction semaphore

	return 0;
}
Compiling this routine, compiling and linking to add - lpthread, run in three cases:

When there is only one thread running at the same time:


When two threads can run simultaneously:


When there are three threads running at the same time:


As can be seen from the above results, using signal quantities can determine how many threads can access shared resources and space at the same time.


Posted by Firestorm ZERO on Tue, 02 Jul 2019 16:43:35 -0700