Linux高并发服务器-Linux多线程开发
线程概述
线程和进程的区别
线程之间的共享和非共享资源
创建线程
main函数所在的线程成为主线程,其余创建的线程为子线程。
程序中默认只有一个进程,fork()调用
程序中默认只有一个线程,pthread_create()函数调用
#include <pthread.h>
//创建一个线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *),void *arg);
参数:
-thread:传出参数,线程创建成功后子线程的线程ID
-attr:设置线程的属性,一般使用默认值,NULL
-start_routine:函数指针,子线程需要除了的逻辑代码
-arg:给第三个参数使用,传参
返回值:成功返回0,失败返回错误号与errno不一样
获取错误号信息 char* strerror(int errnum);
终止线程
//终止一个线程,在哪个线程调用,终止哪个线程
void pthread_exit(void *retval);
参数:
-retval:传递一个指针,作为一个返回值,可以在pthread_join()调用
//获取当前线程ID
pthread_t pthread_self(void);
//比较两个线程号是否相同
int pthread_equal(pthread_t t1, pthread_t t2);
连接已终止的进程
//和一个已终止的线程连接
int pthread_join(pthread_t thread, void **retval);
回收子线程的资源
是阻塞函数,调用一次只能回收一个子线程
一般在主线程使用
-参数:
-thread:需要回收的子线程ID
-retval:子线程退出的返回值 //二级指针
返回值:
成功:0 失败:非0,错误号
retval二级指针:
函数pthread_exit()返回的retval是一个指针,接受这个返回值需要定义一个 int*thread_retval
直接将thread_retval传入参数,他就是一个局部参数,thread_retval的值不会变
改变值要传递地址,所以传&thread_retval,thread_retval是一个指针,&取地址,就变成**的参数类型
线程分离
被分离的线程在终止的时候,会自动返回资源
不能多次分离,会产生不可预料的行为
不能去连接一个已经分离的线程
//分离一个线程,
int pthread_detach(pthread_t thread);
返回值:
成功:0 失败:非0,错误号
线程取消
取消某个线程,可以终止某个线程的运行
但并不是马上取消,而是当子线程执行到一个取消点,线程才会终止
取消点:系统规定好的一些系统调用,从用户区到内核区的切换位置
//取消线程(让线程终止)
int pthread_cancel(pthread_t thread);
线程属性
//初始化线程属性变量
int pthread_attr_init(pthread_attr_t *attr);
//释放线程属性资源
int pthread_attr_destroy(pthread_attr_t *attr);
//获取线程分离的状态属性
int pthread_attr_getdetachstate(const pthread_attr_t *attr,int *detachstate);
//设置线程分离的状态属性
int pthread_attr_setdetachstate(const pthread_attr_t *attr,int detachstate);
...
man pthread_attr_ Tab*2
线程同步
互斥锁mutex
互斥量类型 pthread_mutex_t
//初始化互斥量
int pthread_mutex_init(pthread_mutex_t*restrict mutex,const pthread_mutexattr_t*restrict attr)
-参数:
-mutex:需要初始化的互斥量变量
-attr:互斥量相关的属性,NULL
-restrict: C语言修饰符,被修饰的指针,不能由另外的一个指针进行操作
//释放互斥量资源
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_rwlock_t
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t*restrict attr);
int pthread_rwwlock_destroy(pthread_rwlock_t* rwlock)
int pthread_rwwlock_rdlock(pthread_rwlock_t* rwlock)
int pthread_rwwlock_tryrdlock(pthread_rwlock_t* rwlock)
int pthread_rwwlock_wrlock(pthread_rwlock_t* rwlock)
int pthread_rwwlock_trywrlock(pthread_rwlock_t* rwlock)
int pthread_rwwlock_unlock(pthread_rwlock_t* rwlock)
生产者-消费者模型
生产者消费者模型中的对象:
- 生产者
- 消费者
- 容器
条件变量
条件变量类型 pthread_cond_t
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, const struct timespec *restrict abstime);
//唤醒一个或多个等待线程
int pthread_cond_signal(pthread_cond_t *cond);
//唤醒所有等待的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
信号量
信号量的类型 sem_t
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
-pshared:0 在线程间 非0 在进程间
-value:信号量的值
int sem_destroy(sem_t *sem);
//-1
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
//+1
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem, int *sval);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话