The eighth week of information security system implementation and Design -- self study of Chapter 4 of Unix/Linux system programming

Chapter 4 concurrent programming

This chapter mainly introduces the related contents of concurrent programming, including parallel computing, sequential algorithm and parallel algorithm, parallelism and concurrency; This paper explains the principle of thread and the advantages of machine over process. At the same time, it also carries out the actual operation of thread management and concurrent programming, so that we can have a deeper understanding of the principles and methods of multitasking, thread synchronization and concurrent programming.

4.1 parallel computing

(1) Background:

Early computers had only one processing component, called processor or central processing unit. Most programs performed serial computing, and the algorithm based on divide and conquer principle was highly parallel. Therefore, there was a parallel computing scheme that tried to use multiple processors executing parallel computing to solve the problem.

(2) Sequential algorithm and parallel algorithm

All steps of the sequential algorithm are executed in sequence through a single step. When all steps are completed, the algorithm ends.

In the parallel algorithm, the steps in the same code block are executed in parallel, and the steps of the next code block are executed after all are completed.

4.2 threads

(1) Thread principle

An operating system contains many concurrent processes. In the process model, a process is an independent execution unit. All processes are performed in kernel mode and user mode.

Kernel mode: each process executes in a unique address space, which is separate from other processes. Multiple independent processes share the same execution path. When a process must wait for an event, the whole process will stop executing.

A thread is an independent execution unit of a process in the same address space. To create a process is to create a main thread in a unique address space.

(2) Thread advantages

1. Faster thread creation and switching

2. The response speed of the thread is faster

3. Threads are more suitable for parallel computing

(3) Thread disadvantages

1. Due to address space sharing, the county needs explicit synchronization from users

2. Many library functions may be thread unsafe

3. On a single CPU system, using threads to solve problems is actually slower than using sequential programs.

4.3 thread operation

The execution trajectory of a thread is similar to that of a process. Users can do this in kernel mode or user mode

In user mode, threads execute in the same address space of the process, but each thread has its own execution stack. Thread is an independent execution unit. It can make system calls to the kernel according to the kernel scheduling policy of the operating system. It becomes suspended, activated and continued execution.

4.4 thread management function

1. Creating threads using pthread_ The create() function creates a thread

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

2. The thread ID uses pthread_ The equal() function compares thread IDs

int pthread_equal(pthread_t t1,pthread_t t2); 
Different threads return 0, otherwise non-0 `

3. Thread termination a thread can call a function to terminate

 void pthread_exit(void *status); 
 0 Exit value indicates normal termination, and non-zero value indicates abnormal termination 

4. Thread connection a thread can wait for the termination of another thread and terminate the exit state of the thread through the function.

int pthread_join (pthread_t thread, void **status ptr); `

4.5 thread synchronization

When multiple threads try to modify a shared variable or data structure at the same address, if the modification result depends on the execution order of the threads, it is called a static condition.

(1) Mutex

The simplest synchronization tool is a lock, which allows the executing entity to continue execution only if there is a lock. In Pthread, locks are called mutexes. They must be initialized before use.

There are two ways to initialize mutex addresses:

Static method: pthreaa—mutex_t m = PTHREAD_MUTEX_INITIALIZER; 
    Define mutex m, And initialize it with default properties. 

Dynamic methods: Using pthread_ mutex _init() Function, available through attr Parameter sets the mutually exclusive property. 

(2) Deadlock prevention

Mutex uses blocking protocol. If a thread cannot get the mutex, it will be blocked and continue after the mutex is unlocked. In any blocking protocol, misuse of locking may cause some problems. The most common and prominent problem is deadlock.

There are many methods to solve possible deadlock problems, including deadlock prevention, deadlock avoidance, deadlock detection and recovery.

In the actual system, the only feasible method is deadlock prevention, trying to prevent deadlock when designing parallel algorithms. A simple deadlock prevention method is to sort mutexes and ensure that each thread requests mutexes in only one direction, so that there will be no loops in the request sequence.

(3) Conditional variable

As a lock, mutex is only used to ensure that threads can only access shared data objects in critical areas. Conditional variables provide a way for threads to collaborate.

In Pthread, use the type pthread_cond_t to declare condition variables, and must be initialized before use. Condition variables can be initialized in two ways:

Static method :When declared, define a condition variable con,And initialize it with default properties, such as:
pthread_cond_t con = PTHREAD_COND_INITALLIZER;

Dynamic method :use pthread_cond_init()Functions, by attr Parameter sets the condition variable. 

(4) Semaphore

The main difference between semaphores and conditional variables is that the former includes a counter, operability counter, and tests the counter value to make decisions, while the latter requires a specific mutex to execute the critical area.

5.1 practice

According to example 4.2 in the book, the final code is as follows:

#include <stdio.h>

#include <stdlib.h>

#include <pthread.h>

typedef struct{

	int upperbound;
	
	int lowerbound;

}PARM;


#define N 10

int a[N]={5,1,6,4,7,2,9,8,0,3};// unsorted data

int print(){//print current a[] contents

	int i;
	
	printf("[");
	
	for(i=0;i<N;i++)
	
		printf("%d ",a[i]);
	
	printf("]\n");

}

void *Qsort(void *aptr){

	PARM *ap, aleft, aright;
	
	int pivot, pivotIndex,left, right,temp;
	
	int upperbound,lowerbound;
	
	pthread_t me,leftThread,rightThread;
	
	me = pthread_self();
	
	ap =(PARM *)aptr;
	
	upperbound = ap->upperbound;
	
	lowerbound = ap->lowerbound;
	
	pivot = a[upperbound];//pick low pivot value
	
	left = lowerbound - 1;//scan index from left side
	
	right = upperbound;//scan index from right side
	
	if(lowerbound >= upperbound)
	
		pthread_exit (NULL);
	
	while(left < right){//partition loop
	
		do{left++;} while (a[left] < pivot);
	
		do{right--;}while(a[right]>pivot);
	
		if (left < right ) {
	
			temp = a[left];a[left]=a[right];a[right] = temp;
	
		}
	
	}
	
	print();
	
	pivotIndex = left;//put pivot back
	
	temp = a[pivotIndex] ;
	
	a[pivotIndex] = pivot;
	
	a[upperbound] = temp;
	
	//start the "recursive threads"
	
	aleft.upperbound = pivotIndex - 1;
	
	aleft.lowerbound = lowerbound;
	
	aright.upperbound = upperbound;
	
	aright.lowerbound = pivotIndex + 1;
	
	printf("%lu: create left and right threadsln", me) ;
	
	pthread_create(&leftThread,NULL,Qsort,(void * )&aleft);
	
	pthread_create(&rightThread,NULL,Qsort,(void *)&aright);
	
	//wait for left and right threads to finish
	
	pthread_join(leftThread,NULL);
	
	pthread_join(rightThread, NULL);
	
	printf("%lu: joined with left & right threads\n",me);

}

	int main(int argc, char *argv[]){
	
	PARM arg;
	
	int i, *array;
	
	pthread_t me,thread;
	
	me = pthread_self( );
	
	printf("main %lu: unsorted array = ", me);
	
	print( ) ;
	
	arg.upperbound = N-1;
	
	arg. lowerbound = 0 ;
	
	printf("main %lu create a thread to do QS\n" , me);
	
	pthread_create(&thread,NULL,Qsort,(void * ) &arg);//wait for Qs thread to finish
	
	pthread_join(thread,NULL);
	
	printf ("main %lu sorted array = ", me);
	
	print ("20191303jcy\n") ;


}

The practical screenshot is as follows:

5.2 problems and Solutions

An error is reported during the specific operation, as shown in screenshot 1. After asking the students, it is judged that there is a problem with the compilation. Since the POSIX standard of threads is involved, it is necessary to use Pthread command line tool in Unix operating system

gcc -pthread

Command to compile, and the final result is shown in Figure 2 above

Posted on Sun, 31 Oct 2021 07:02:05 -0400 by xfezz