linux system programming thread

What is a thread

A process does only one thing at a time. With multiple control threads, the process can be designed to do more than one thing at the same time, and each thread handles independent tasks. Process is an instance of program execution and the basic unit for allocating system resources. In the system of thread oriented design, the process itself is not the basic running unit, but the container of threads. Thread is the smallest unit that the operating system can schedule operations. It is included in the process and is the actual operation unit in the process. A thread refers to a single sequential control flow in a process. Multiple threads can be concurrent in a process, and each thread executes different tasks in parallel. Processes have independent address space. After a process crashes, it will not affect other processes in protected mode, and threads are only different execution paths in a process. Threads have their own stack and local variables, but threads do not have a separate address space. The death of a thread will lead to the death of the whole process. Therefore, multi-process programs are more robust than multi-threaded programs, but they consume more resources and are less efficient when switching processes. Compared with processes, threads are relatively simple because they share data segments with other threads, and the communication mechanism will be relatively simple.

API

The library required for multithreading programming is supported by pthread library on linux. Programming basically includes three points: thread operation, mutex and condition.

Thread operation

#include<pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
void pthread_exit(void *retval);
int pthread_join(pthread_t thread, void **retval);

①pthread_create: thread creation
Thread: is the thread ID. when the create succeeds, the ID number is also set successfully
attr: thread attribute. Generally, NULL can be set to set the default attribute
start_routine: thread function pointer. The parameter type is a typeless pointer
arg: is the parameter passed to the thread. If you want to pass multiple groups of data, you can define a structure
②pthread_join: the thread waits until the target thread exits
Thread: ID of the thread to wait for
retval: it will contain the return code of the thread. If you don't care about the returned status, you can set it to NULL
③pthread_exit: the thread exits
retval: exit code

Here is an example. Note that the chain library, - lpthread is required for compilation

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
void *func2(void * data){
        printf("in the thread2\n");
        sleep(2);
        printf("func2 quit!!!\n");
        pthread_exit(0);

}
void *func1(void * data){
        printf("in the thread1\n");
        printf("The parameter passed is:%d\n",*(int *)data);
        printf("Thread 1 ID: %ld\n",pthread_self());
        sleep(2);
        printf("func1 quit!!!\n");

        pthread_exit(0);
}
int main(){
        pthread_t t1;
        pthread_t t2;
        int data=20;
        int *ret;

        pthread_create(&t1,NULL,func1,(void *)&data);
        pthread_create(&t2,NULL,func2,(void *)&data);

        printf("main: %ld\n",pthread_self());
        pthread_join(t1,(void*)&ret);
        pthread_join(t2,(void*)&ret);


        return 0;
}

mutex

#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

①pthread_mutex_init: create mutex, create dynamically
Mutex mutex name.
attr is the property of the mutex. You can set NULL as the default property here
If you want to use statically created methods, you can use a macro PTHREAD_MUTEX_INITIALIZER, and then define a mutex for this macro without using the init function
②pthread_mutex_destroy: destroy mutex
③pthread_mutex_lock: add mutex lock
④pthread_mutex_unlock: Unlock mutex
⑤pthread_mutex_trylock: try to unlock the mutex
Mutex is a mutex that needs to be operated. When one thread takes the lock and another thread tries to call lock before unlocking, it will block there. If another thread calls trylock instead of lock, it will judge whether the mutex is locked. If not, it will be locked. If locked, it will fail to lock, but it will not block

deadlock

What is deadlock? When a program is running and in a multithreaded task, a thread locks a mutex and is ready to lock another mutex before unlocking the mutex. At this time, the mutex is being locked and unlocked by the second thread, The second thread also wants to lock the locked mutex in the first thread, and two threads will block in the process at the same time. At this time, trylock can solve the deadlock.

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

pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
void *func3(void * data){
		printf("in the thread3\n");
        pthread_mutex_lock(&mutex1);
        sleep(1);
        pthread_mutex_trylock(&mutex2);
		printf("func3 arrive!!!\n");
        pthread_mutex_unlock(&mutex1);
        pthread_mutex_unlock(&mutex2);
        }
void *func2(void * data){
		 printf("in the thread2\n");
        pthread_mutex_lock(&mutex2);
        sleep(1);
        pthread_mutex_trylock(&mutex1);
        printf("func2 arrive!!!\n");
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex1);
}
         void *func1(void * data){
        printf("in the thread1\n");
        printf("The parameter passed is:%d\n",*(int *)data);
}
int main(){
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;
        int data=20;
        int *ret;

        pthread_mutex_init(&mutex1,NULL);
        pthread_mutex_init(&mutex2,NULL);
        pthread_create(&t1,NULL,func1,(void *)&data);
        pthread_create(&t2,NULL,func2,(void *)&data);
        pthread_create(&t3,NULL,func3,(void *)&data);

        printf("main: %ld\n",pthread_self());
        pthread_join(t1,(void*)&ret);
        pthread_join(t2,(void*)&ret);
        pthread_join(t3,(void*)&ret);
        pthread_mutex_destroy(&mutex1);
        pthread_mutex_destroy(&mutex2);


        return 0;
}



As can be seen from the code, the preparation here is to force deadlock, but because trylock is used, the thread will not block

condition

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict ti
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);

①pthread_cond_init: create condition variables and create them dynamically
cond: condition variable name, attribute of attr condition. It can still be set to NULL here and created with the default attribute
You can also use a macro PTHREAD_COND_INITIALIZER to create statically. When this macro is used, the init function is unnecessary
②pthread_cond_destroy: destroy condition variable
③pthread_cond_wait: wait for another thread to send a signal, otherwise the thread will block
④pthread_cond_timedwait: similar to wait, but with a timed time
⑤pthread_cond_signal: wake up a thread that meets this condition
⑥pthread_cond_broadcast: wake up all threads that meet this condition. If you want to wake up all threads, the mutexes in the waiting threads need to be different. Otherwise, the effect is the same as that of the signal function. You can only wake up a single thread.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
pthread_cond_t cond;
void *func3(void * data){
        printf("in the thread3\n");
        pthread_cond_wait(&cond,&mutex1);
        printf("func3 arrive!!!\n");
}
void *func2(void * data){
        printf("in the thread2\n");
        pthread_cond_wait(&cond,&mutex2);
        printf("func2 arrive!!!\n");
}
void *func1(void * data){
        printf("in the thread1\n");
        printf("The parameter passed is:%d\n",*(int *)data);
        printf("Thread 1:%ld\n",pthread_self());
        pthread_mutex_lock(&mutex1);
        pthread_mutex_lock(&mutex2);
    	sleep(3);
        pthread_cond_broadcast(&cond);
        pthread_mutex_unlock(&mutex1);
        pthread_mutex_unlock(&mutex2);
}
int main(){
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;
        int data=20;
        int *ret;

        pthread_mutex_init(&mutex1,NULL);
        pthread_mutex_init(&mutex2,NULL);
        pthread_cond_init(&cond,NULL);
        pthread_create(&t1,NULL,func1,(void *)&data);
        pthread_create(&t2,NULL,func2,(void *)&data);
        pthread_create(&t3,NULL,func3,(void *)&data);

        printf("main: %ld\n",pthread_self());
        pthread_join(t1,(void*)&ret);
        pthread_join(t2,(void*)&ret);
        pthread_join(t3,(void*)&ret);
        pthread_mutex_destroy(&mutex1);
        pthread_mutex_destroy(&mutex2);

        pthread_cond_destroy(&cond);

        return 0;
}



It can be seen here that when there are two mutexes in thread 1, the corresponding mutexes in the two threads to be awakened are also different, so they can be awakened at the same time

Keywords: C Linux Multithreading

Added by JAM on Fri, 14 Jan 2022 11:26:01 +0200