1--Advantages of multi-threading
Disadvantages of multi-process servers:
① The process of creating a process will bring certain overhead;
② In order to complete data exchange between processes, special IPC technology is required;
③ Context switching between processes is the largest overhead when creating a process;
Advantages of multithreading:
① Thread creation and context switching are faster than process creation and context switching;
② No special technology is required when exchanging data between threads;
2--The difference between processes and threads
Each process has an independent memory space and its own data area, heap area and stack area;
Each thread only has its own stack area, and the data area and heap area are shared between threads; therefore, there is no need to switch the data area and heap when context switching between threads, and the data area and heap area can be used to exchange data;
Process: A unit that constitutes a separate execution flow in the operating system;
Thread: A unit that forms a separate execution flow in a process;
A process generates multiple execution streams within the operating system, and a thread creates multiple execution streams within the same process;
3--Thread creation
#include <pthread.h>
int pthread_create(pthread_t* restrict thread, const pthread_attr_t* restrict attr, void* (* start_routine)(void*), void* restrict arg);
// 成功时返回 0,失败时返回其他值
// thread 表示保存新创建线程 ID 的变量地址值
// attr 表示用于传递线程属性的参数,传递 NULL 时表示创建默认属性的线程
// start_routine 表示线程的入口函数
// arg 表示传递给线程入口函数的参数
// gcc thread1.c -o thread1 -lpthread
// ./thread1
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_main(void* arg){ // 线程入口函数
int i;
int cnt = *((int*)arg);
for(i = 0; i < cnt; i++){
sleep(1);
puts("running thread");
}
return NULL;
}
int main(int argc, char* argv[]){
pthread_t t_id;
int thread_param = 5;
if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){ // 创建线程
puts("pthread_create() error");
return -1;
}
sleep(10);
puts("end of main");
return 0;
}
4--Thread usage
Calling pthread_join(ID) can put the process or thread into a waiting state until the thread corresponding to the ID terminates;
#include <pthread.h>
int pthread_join(pthread_t thread, void** status);
// 成功时返回0,失败时返回其他值
// thread 表示线程ID,只有该线程终止后才会从函数返回
// status 表示保存线程返回值的指针变量地址值
// gcc thread2.c -o thread2 -lpthread
// ./thread2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
void* thread_main(void *arg){
int i;
int cnt = *((int*)arg);
char* msg = (char*)malloc(sizeof(char)*50);
strcpy(msg, "Hello, I'm thread~ \n");
for(i = 0; i < cnt; i++){
sleep(1);
puts("running thread");
}
return (void*)msg;
}
int main(int argc, char* argv[]){
pthread_t t_id;
int thread_param = 5;
void* thr_ret;
// 创建线程
if(pthread_create(&t_id, NULL, thread_main, (void*)&thread_param) != 0){
puts("pthread_create() error");
return -1;
}
// 阻塞,等待线程返回
if(pthread_join(t_id, &thr_ret) != 0){
puts("pthread_join() error");
return -1;
}
// 打印线程返回值
printf("Thread return message: %s \n", (char*)thr_ret);
free(thr_ret);
return 0;
}
5--Thread safety issues
Problems may occur when multiple threads call functions to execute critical section code at the same time;
Depending on whether the critical section causes problems, functions can be divided into: thread-safe functions and non-thread-safe functions;
Thread-safe functions will not cause problems when called by multiple threads at the same time, but problems will occur when non-thread-safe functions are called at the same time;
The following code shows that unexpected problems may occur when multiple threads access critical section code to operate global variables at the same time;
// gcc thread4.c -D_REENTRANT -o thread4 -lpthread
// ./thread4
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREAD 100
long long num = 0;
void* thread_inc(void* arg){
int i;
for(i = 0; i < 50000000; i++){
num += 1;
}
return 0;
}
void* thread_des(void* arg){
int i;
for(i = 0; i < 50000000; i++){
num -= 1;
}
return 0;
}
int main(int argc, char* argv[]){
pthread_t thread_id[NUM_THREAD];
int i;
printf("sizeof long long: %ld \n", sizeof(long long));
for(i = 0; i < NUM_THREAD; i++){
// 各创建50个线程,分别执行对全局变量 num 的加减操作
if(i%2){
pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);
}
else{
pthread_create(&(thread_id[i]), NULL, thread_des, NULL);
}
}
for(i = 0; i < NUM_THREAD; i++){
pthread_join(thread_id[i], NULL);
}
printf("result: %lld \n", num);
return 0;
}
The normal result should be 0, but the actual result is not; this is when multiple threads access the critical section at the same time, and problems such as data competition will occur;
When a thread accesses the variable num, other threads should be prevented from accessing it until one thread completes the operation. This is synchronization; thread synchronization is used to solve problems caused by the order of thread access;
6--Mutex
A mutex means that multiple threads are not allowed to access at the same time, and it is mainly used to solve the problem of thread synchronization access;
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr);
int pthread_mutex_destroy(pthread_mutex_t* mutex);
// 成功时返回 0,失败时返回其他值
// mutex 表示创建和销毁互斥量时传递保存和销毁互斥量的变量地址值
// attr 传递即将创建的互斥量属性,没有特别需要指定的属性时传递 NULL
int pthread_mutex_lock(pthread_mutex_t* mutex); // 上锁
int pthread_mutex_unlock(pthread_mutex_t* mutex); // 解锁
// 成功时返回 0,失败时返回其他值
pthread_mutex_t mutex;
pthread_mutex_lock(&mutex);
// 临界区开始
// ...
// 临界区结束
pthread_mutex_unlock(&mutex);
7--Signal amount
Use binary semaphores to complete the synchronization method centered on the control thread program;
#include <semaphore.h>
int sem_init(sem_t* sem, int pshared, unsigned int value);
int sem_destroy(sem_t* sem);
// 成功时返回 0,失败时返回其他值
// sem 表示信号量的变量地址值
// pshared 传递其他值时,创建可由多个进程共享的信号量;传递 0 时,创建只允许一个进程内部使用的信号量
// value 表示指定新创建的信号量的初始值
int sem_post(sem_t* sem); // 信号量增加1
int sem_wait(sem_t* sem); // 信号量减少1
// 成功时返回 0,失败时返回其他值
sem_wait(&sem); // 信号量变为0
// 临界区的开始
// ...
// 临界区的结束
sem_post(&sem); // 信号量变为1
8--Thread destruction
3 ways to destroy threads:
① Call the return statement of the main function;
② Call the pthread_join() function;
③ Call the pthread_detach() function;