Linux系统编程——多线程

线程是独立调度的基本单位。一个进程可以有一个或者多个线程,线程之间共享进程资源。

线程分类

按调度者分为:

  • 用户级线程(User Level Thread,ULT)

    解决上下文切换问题,调度算法和过程由用户决定
    存在于用户空间
    线程创建、撤销以及线程之间的同步、通信无需系统调用来实现
    同一进程的线程切换不需要内核支持
    调度以进程为单位
    

    优点:

    线程切换不需要到内核空间,节省内核空间
    调度算法可以进程专用,亦或用户程序指定
    用户线程实现与操作系统无关
    

    缺点:

    同一进程一个线程执行系统调用阻塞就导致进程阻塞
    一个进程只能在一个CPU上获得执行,无法发挥SMP(对称多处理器)的优势
    
  • 核心级线程(kernel Supported threads,KST)

    不同进程的线程按照同一相对优先调度算法调度,发挥SMP优势
    线程创建撤销、以及切换等等通过系统调用陷入内核由内核响应程序处理
    调度以线程为基本单位
    

    优点:

    在SMP情况下,内核可以调度同一进程通中的多个线程并发工作
    同一线程的一个线程阻塞,其他线程依然可以运行
    

​ 缺点:

      主要是程序在内核态和用户态之间切换带来的开销

线程相关API

线程的创建:

pthread_create - create a new thread  //创建一个新线程

//头文件
#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
thread —— 新线程TID(Thread id 类似进程的pid)
attr  —— 线程属性,为NULL创建一个标准线程
start_routine —— 线程入口函数
arg —— 线程入口参数

RETURN VALUE
  成功返回0; 错误返回errno, and the contents of *thread are undefined.

errno —— 一个全局变量,存放各种API执行失败的原因

线程的退出:

  • 线程入口函数调用return语句并指定返回值
  • 线程调用pthread_exit()
  • 调用pthread_cancel取消线程
  • 任意线程调用exit()或者main线程调用了return,都将导致所有线程退出
pthread_exit - terminate calling thread 

#include <pthread.h>

void pthread_exit(void *retval);  //线程退出
retval —— 退出值

Compile and link with -pthread.//编译要链接pthread库

线程取消:

pthread_cancel - send a cancellation request to a thread //发送取消线程请求

#include <pthread.h>

int pthread_cancel(pthread_t thread);  //取消线程

RETURN VALUE
    成功 pthread_cancel() 返回 0; 失败, 返回非零 error number.

获取线程的退出值

pthread_join - join with a terminated thread

#include <pthread.h>  

int pthread_join(pthread_t thread, void **retval); //获取线程退出值
thread —— 线程TID
retval —— 线程退出值

RETURN VALUE
    成功 pthread_join()  0; 失败返回 error  number.

获取自身TID:

pthread_self - obtain ID of the calling thread

#include <pthread.h>

pthread_t pthread_self(void);

RETURN VALUE
	成功返回线程TID,不存在失败

创建标准线程:

/***************************************************************************************************
  * @file:     xxx.c
  * @author:   guangjieMVP
  * @github:  
  * @version:  v1.0.0
  * @date:     2020-xx-xx
  * @brief:               
*****************************************************************************************************/
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

int retval = 0xff;
void *thread1_entry(void *arg)
{
    
    
    static int cnt = 0;
    
    while (1)
    {
    
    
        printf("Linux %d\r\n", cnt++);
        if(cnt >= 10)
        {
    
    
            cnt = 0;
            pthread_exit(&retval);
        }
        sleep(2);
    }
}

void *thread2_entry(void *arg)
{
    
    
    while (1)
    {
    
    
        printf("ubuntu\r\n");
        sleep(3);
    }
}

int main(int argc, char **argv)
{
    
    
    pthread_t thread1;
    pthread_t thread2;

    pthread_create(&thread1, NULL, thread1_entry, NULL);  //attr为NULL——使用默认属性创建thread
    pthread_create(&thread2, NULL, thread2_entry, NULL);
    
    static int maincnt = 0;
    unsigned char flag = 0;
    while(1)
    {
    
    
        printf("main thread %d\r\n", maincnt++);
        if(maincnt >= 10 && !flag)
        {
    
    
            maincnt = 0;
            flag = 1;
            pthread_cancel(thread2);
        }
        sleep(1);
    }
    
    return 0;
}

编译执行:

gcc pthread_create.c -o pthread_create -lpthread  //编译程序

//-lpthread —— 链接pthread线程库
    
./pthread_create  //执行程序

线程分离与接合

默认情况下线程是可连接状态——线程退出时不会释放资源,其他线程可以通过pthread_join()获取其退出值

不关心线程返回状态可以把线程设置为可分离的——线程结束系统自动释放并清理资源,线程必定不会成为僵尸线程s

pthread_detach - detach a thread  //设置线程属性为分离

#include <pthread.h>

int pthread_detach(pthread_t thread);
thread —— 线程ID

RETURN VALUE
    成功返回0; 失败, 返回errno

线程属性

线程属性包含属性:线程栈的大小和位置、调度策略、优先级等以及线程是分离还是可连接
pthread_attr_init, pthread_attr_destroy - initialize and destroy thread attributes object   //初始化或者销毁销毁线程属性
头文件
#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr); //初始化线程属性
int pthread_attr_destroy(pthread_attr_t *attr);//销毁线程属性
attr —— 线程属性

pthread_attr_setdetachstate,  pthread_attr_getdetach‐state - 设置or获取线程的分离状态

#include <pthread.h>

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
attr —— 线程属性
detachstate —— 分离状态:
      PTHREAD_CREATE_DETACHED — 分离状态
      PTHREAD_CREATE_JOINABLE — 可连接状态

RETURN VALUE
   成功返回0; 失败返回非0的errno

分离属性创建线程:

    int ret;
    pthread_attr_t attr; //定义线程属性变量
    
    ret = pthread_attr_init(&attr); //初始化线程属性变量
    if(ret != 0)
    {
    
    
        printf("faild to init attr\r\n");
        exit(0);
    }
    
    ret = pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);//设置线程为分离状态
    if(ret != 0)
    {
    
    
        printf("faild to setdetach\r\n");
        exit(0);
    }
    pthread_create(&thread1, &attr, thread1_entry, NULL); //使用attr属性创建线程
    pthread_create(&thread2, &attr, thread2_entry, NULL);

设置以及获取线程调度策略

pthread_attr_setschedpolicy, pthread_attr_getschedpolicy - 获取or设置线程调度策略

#include <pthread.h>

int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy); //设置线程调度策略
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
attr —— 线程属性

policy —— 调度策略
      SCHED_FIFO —— 以先进先出的派对方式调度,处于就绪就会被立即放入所在优先级队列队尾
                    被更高优先级抢占后会被放入所在优先级队列队头,高优先级运行结束其立即
                    恢复运行
                    可以调用sched_yield()主动让出CPU
      SCHED_RR   —— 以轮转的方式调度, 线程会被分配一定的时间片,
                    时间片耗尽会被放入所在优先级队列的队尾
      SCHED_OTHER —— 非实时调度的普通线程,静态优先级必须设置为0,使用Linux系统默认的调度策略——按照动态优先级调度

RETURN VALUE
       On success, these functions return 0; on error,  they  return  a  nonzero error number.


获取、设置线程调度策略以及静态优先级


 pthread_attr_setschedparam,  pthread_attr_getschedparam  - 设置、获取静态线程优先级

#include <pthread.h>
       
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);
//attr —— 线程属性
//param —— 线程静态优先级

RETURN VALUE
    On  success,  these  functions  return  0;  on error, they return a nonzero error number.

获取、设置线程调度策略以及静态优先级

pthread_setschedparam,  pthread_getschedparam - 设置or获取线程调度策略以及静态优先级

#include <pthread.h>

int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param); //设置调度策略以及静态优先级
int pthread_getschedparam(pthread_t thread, int *policy, struct sched_param *param);
//thread —— 线程TID
//policy —— 调度策略
//param —— 静态优先级

 struct sched_param {
    
    
     int sched_priority;     /* Scheduling priority */
};

获取、设置线程动态优先级

nice - change process priority

 #include <unistd.h>

int nice(int inc);

线程栈

线程创建后都有一个线程栈,缺省情况下大小固定。线程栈大小可以改变

#include <pthread.h>

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
attr —— 线程属性结构体
stackaddr —— 线程栈地址
stacksize —— 线程栈大小

RETURN VALUE
    成功返回0;失败返回非零错误编码

猜你喜欢

转载自blog.csdn.net/qq_36413982/article/details/107167390