IO进程线程(线程)

发布于:2025-07-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、线程

1、线程的概念

线程:是进程并发执行多个任务(线程)的机制,同进程下的多个线程共用同一进程资源。

进程:是由一个或多个线程组成的

        串行:多个任务在单核CPU上按顺序执行

        并发:多个任务在单核CPU上,以时间片轮机制执行

        并行:多核CPU同时执行多个任务

2、进程和线程的区别

1. 进程之间用户空间独立,内核资源共享,,线程共享进程的资源

2. 进程是资源分配日的最小单位,线程是任务执行的最小单位

3. 多进程之间需要引入进程间通讯机制(IPC),多线程之间需要引入同步互斥

4. 进程的资源比线程多

5. 线程的效率比进程高

6. 进程的稳定性比线程强

3、线程的函数

1)安装线程的man手册

安装线程:sudo apt-get install manpages-posix*

注意如果出现锁的错误,解决方式:删除以下两个文件

rm /var/lib/dpkg/lock lock-frontend

2)pthread_create

格式:   
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
          void *(*start_routine) (void *), void *arg);
          
Compile and link with -pthread.
功能:在进程内创建一个新的线程
参数:
    pthread_t *thread:该指针指向的内存中存储线程id  
    const pthread_attr_t *attr:线程的属性(线程的描述信息),写NULL,表示默认属性(结合态)
                                可以通过pthread_attr_init 修改属性,分离态
    void *(*start_routine) (void *): 创建的线程函数名,该函数必须是函数指针
    arg:表示线程体的参数,可以写NULL

返回值:
    成功返回0
    失败方error number,此时线程id未被定义

1. 分支线程结束,主线程不会结束
2. 主线程结束,分支线程也会结束
3. 分支线程和主线程都可以使用全剧变量
4. 分支线程使用主线程的局部变量

5. 主线程访问分支线程的局部变量

6. 主线程访问分支线程的变量的地址(使用分支线程的局部变量)

3)pthread_self(获取线程ID)

格式:
    #include <pthread.h>
    pthread_t pthread_self(void);
    Compile and link with -pthread. --->  编译的时候需要加 -pthread
功能:获取调用线程的线程id
返回值:返回调用者的线程id

4)pthread_exit(结束线程)

格式:
    #include <pthread.h>
    void pthread_exit(void *retval);
    Compile and link with -pthread. --->  编译的时候需要加 -pthread
功能:终止调用线程的,一般用于分支线程
参数:
    void *retval: 线程的返回值,可以写NULL

5)pthread_ join(回收指定函数的资源)

格式:
    #include <pthread.h>
    int pthread_join(pthread_t thread, void **retval);
    Compile and link with -pthread.
功能:阻塞函数,等待接收指定线程的资源,回收指定线程的资源
参数:
    pthread_t thread:阻塞等待接收的指定线程id
    void **retval:接收pthread_exit的退出状态值
        需要指向一级指针的地址,不接收可以写NULL
返回值:
成功返回0,失败返回error number

6)pthread_detach(分离线程)

格式:
    #include <pthread.h>
    int pthread_detach(pthread_t thread);
    Compile and link with -pthread.
功能:分离线程的,结束线程的资源有系统自动回收,不会阻塞
    一旦使用pthread_detach函数,则pthread_join则无效,不会阻塞回收资源
参数:
    pthread_t thread:分离的线程id
返回值:
成功返回0,失败返回error number      

7)pthread_cancel(结束子线程)

格式:
    #include <pthread.h>
    int pthread_cancel(pthread_t thread);    
    Compile and link with -pthread.
功能:对指定子线程发送一个取消(结束)请求(信号),子进程可以选择取消的状态,以及是否结束线程
参数:
    pthread_t thread:指定的子线程id
返回值:
成功返回0,失败返回error number         

8)pthread_setcancelstate(选择是否同意主进程的请求)

格式:
    #include <pthread.h>
    int pthread_setcancelstate(int state, int *oldstate);
功能:设置取消的状态
参数:
    int state:
    PTHREAD_CANCEL_ENABLE,可以取消
    PTHREAD_CANCEL_DISABLE,不可以取消
   int *oldstate:获取上一次的取消状态值的,不想要获取写NULL
返回值:
    成功返回0,失败返回非0的error number 

9)pthread_setcanceltype(选择取消的状态)

格式:
    int pthread_setcanceltype(int type, int *oldtype);
    Compile and link with -pthread.
功能:设置取消类型
参数:
int type:
    PTHREAD_CANCEL_DEFERRED:延时取消(遇到取消点:sleep,printf)
    PTHREAD_CANCEL_ASYNCHRONOUS:立刻取消
int *oldtype:获取上一次的取消类型值的,不想要获取写NULL
返回值:
    成功返回0,失败返回非0的error number 

4、同步互斥

由于线程之间共享资源,不同线程在同时修改同一变量时,会出现数据混乱;

而同步互斥是解决数据混乱的方法。

1)同步互斥问题(如何完成同步互斥操作)

以两个分支线程为例

临界资源:是多个线程抢夺的资源共享资源(全局变量、内核资源、数据库)

临界区:是执行访问临界资源的代码

互斥:同一时间只允许一个线程访问临界资源,具备唯一性,排他性,不确定访问者的顺序

同步:在互斥的基础上,确定访问者的顺序

解决同步互斥问题的方式:同步锁、信号量(信号灯)、条件变量

2)互斥锁

原理

将需要访问临界资源的线程做上锁操作,如果上锁成功则执行代码,如果上锁失败,则等待。

1. pthread_mutex_init(互斥锁初始化)
格式:
 #include <pthread.h>
 方式1:
pthread_mutex_t  fastmutex  = PTHREAD_MUTEX_INITIAL_IZER;
方式2:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
功能:初始化互斥锁
参数:
    pthread_mutex_t *mutex:该指针指向的内存中存储你要初始化的互斥锁
    const pthread_mutexattr_t *mutexattr:互斥锁的属性
        写NULL,默认属性 默认用于线程
        不写NULL,默认进程,或者可以通过 修改其他属性:pthread_mutexattr_init(递归锁,读写锁,自旋锁等)
返回值:
    永远返回0 
2. pthread_mutex_lock(上锁)
格式: int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:上锁,阻塞函数,如果存在锁资源则上锁成功,如果没有锁资源则阻塞等待
参数:pthread_mutex_t *mutex该指针指向的内存中存储你要初始化的互斥锁
返回值:成功返回0,失败返回非0
3. pthread_mutex_unlock(关锁)
格式: int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
参数:pthread_mutex_t *mutex该指针指向的内存中存储你要初始化的互斥锁
返回值:成功返回0,失败返回非0
4. pthread_mutex_destroy(销毁互斥锁,释放内存)
格式:int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁锁,释放锁资源
参数:pthread_mutex_t *mutex该指针指向的内存中存储你要初始化的互斥锁
返回值:成功返回0,失败返回非0
5. pthread_mutex_trylock(尝试上锁)
格式: int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:尝试上锁,非阻塞函数,
    如果存在锁资源则上锁成功,如果没有锁资源则不会阻塞等待,直接向下运行
参数:pthread_mutex_t *mutex该指针指向的内存中存储你要初始化的互斥锁
返回值:成功返回0,失败返回非0
 实列:

6. 生产者、消费者模型(互斥锁完成)

3)信号量(信号灯)

原理:

让访问临界资源的线程都去申请信号量,如果信号量的值大于0,则申请成功,信号量的值减1;

如果信号量的值等于0,则申请失败,阻塞直到信号量的值大于0,解除阻塞,重新申请。

1. sem_init(初始化信号量)
格式 #include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Link with -pthread.
功能:初始化信号量的
参数:
sem_t *sem:该指针中存储信号量
int pshared:
    0:用于线程
    非0:用于进程
unsigned int value:最多允许几个线程同时访问临界资源
返回值:成功返回0,失败返回-1. 跟新errno
2. sem_wait(申请信号量)
格式   #include <semaphore.h>
       int sem_wait(sem_t *sem);
功能:阻塞函数,申请信号量的 P操作,减1
    如果信号量的值大于0,申请成功,值减1
    如果信号量的值等于,则申请失败,阻塞直到信号量的值大于0
参数:sem_t *sem:该指针中存储信号量
返回值:成功返回0,失败返回-1. 跟新errno
3. sem_post(释放信号量)
格式  #include <semaphore.h>
       int sem_post(sem_t *sem);
       Link with -pthread.
功能:释放信号量的  V操作,信号量的值加1
参数:sem_t *sem:该指针中存储信号量
返回值:成功返回0,失败返回-1. 跟新errno
4. sem_destroy(销毁信号量,释放内存)
格式 #include <semaphore.h>
       int sem_destroy(sem_t *sem);
       Link with -pthread.
功能:销毁信号量,释放资源
参数:sem_t *sem:该指针中存储信号量
返回值:成功返回0,失败返回-1. 跟新errno
5. sem_getvalue(访问指定信号量的,还有几个线程可以进程)
#include <semaphore.h>
 int sem_getvalue(sem_t *sem, int *sval);
Link with -pthread.
功能:获取指定信号量还可以允许几个线程访问
参数:
    sem_t *sem:该指针中存储信号量
    int *sval:允许几个线程
返回值:成功返回0,失败返回-1. 跟新errno
6. 生产者、消费者模型(信号量完成)

7. 使用信号量完成多线程写入日志

4)条件变量

原理:

把不需要访问临界资源的线程休眠,并设置一个唤醒条件,这个条件称为条件变量,

当需要访问临界资源时,通过其他线程唤醒。

1. pthread_cond_init(初始化)
格式:
方式1: 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
方式2:
int   pthread_cond_init(pthread_cond_t   *cond,  pthread_con‐
       dattr_t *cond_attr);
功能:初始化条件变量
参数:
pthread_cond_t   *cond:该指针指向的内存中存储条件变量
pthread_cond_attr_t *cond_attr:条件变量的属性
    NULL:默认属性表示线程
    非NULL,表示进程
返回值:
    成功返回0,失败返回非0
2. pthread_cond_wait(睡眠)
格式:
int pthread_cond_wait(pthread_cond_t  *cond,  pthread_mutex_t *mutex);
功能:阻塞函数,解锁,如果其他函数唤醒休眠函数,则上锁的
参数:
    pthread_cond_t  *cond:该指针指向的内存中存储条件变量
    pthread_mutex_t *mutex:互斥锁
返回值:
    成功返回0,失败返回非0

1.为什么条件中会有锁呢
    当多个CPU执行多线程时,例如两个CPU分别同时执行AB线程 ,且AB线程中同时调用
    pthread_cond_wait函数,两个线程需要添加到内核的休眠队列中,
    此时需要使用互斥锁,避免AB线程存放内核休眠队列出现竞态
2.pthread_cond_wait函数执行流程
    1.pthread_mutex_lock
    2.pthread_cond_wait休眠,解锁
    3.假设其他线程唤醒该线程
        尝试上锁,如果上锁失败,则继续休眠,唤醒失败
        上锁成功,则唤醒成功
    4.解锁 pthread_mutex_unlock
            
3.该函数还有可能被被内核发送的某个信号意外唤醒(内核优化)
3. pthread_cond_signal(逐个唤醒)
格式:int pthread_cond_signal(pthread_cond_t *cond);
功能:唤醒休眠队列中的第一个线程
参数:pthread_cond_t   *cond:该指针指向的内存中存储条件变量
返回值:
    成功返回0,失败返回非0
4. pthread_cond_broadcast(全部唤醒)
格式: int pthread_cond_broadcast(pthread_cond_t *cond);
功能:唤醒休眠队列中的多有线程
参数:pthread_cond_t   *cond:该指针指向的内存中存储条件变量
返回值:
    成功返回0,失败返回非0
5. pthread_cond_destroy(条件变量)
格式:  int pthread_cond_destroy(pthread_cond_t *cond);
功能:销毁信号量,释放资源
参数:pthread_cond_t   *cond:该指针指向的内存中存储条件变量
返回值:
    成功返回0,失败返回非0
6. 条件变量的使用

作业:

1. 创建一个分支线程,在主线程中拷贝文件的前一部分,分支线程拷贝文件的后一部分

2. 解读代码

info 1 from child procsee_1
info 1 from child procsee

3. 解读代码(输出8次)

 


网站公告

今日签到

点亮在社区的每一天
去签到