Linux高并发服务器-Linux多线程开发

线程概述

Alt text

线程和进程的区别

Alt text

线程之间的共享和非共享资源

Alt text

创建线程

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

线程同步

Alt text

互斥锁mutex

Alt text
Alt text

互斥量类型 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)

死锁

Alt text

读写锁

Alt text

读写锁类型 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)

生产者-消费者模型

生产者消费者模型中的对象:

  1. 生产者
  2. 消费者
  3. 容器

条件变量

条件变量类型 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);
posted @   玩世不恭xxh  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示