进程中的执行分支——线程

线程背景

进程:为了并发执行任务(程序),现代操作系统才引进 进程 的概念
开销分析:

创建开销问题:创建一个进程开销大:子进程需要拷贝父进程的整个地址空间

通信开销问题:进程间的通信需要用第三方 (如:内核)P1 -> copy -> 内核 -> copy -> P2
进程间通信代价或者开销也是很大的。进程的地址空间是独立,要通信的话需要用第三方的空间。

于是,就有人提出能不能在 同一个(同一个进程内部)进程地址空间中进行任务的并发:线程/轻量级 进程

线程

线程是一个比进程更小的活动单位。它是进程中的执行路径(执行分支),线程也是并发的一种形式。

进程内部可以存在多个线程,它并发执行,但是进程内部的所有的线程共享整个进程的地址空间

eg: main 函数:进程的主线程
线程之间的关系

线程特点

创建一个线程要比创建进程开销要小很多
因为创建一个线程的话,不需要拷贝进程的地址空间
实现线程间的通信会更加方便
因为进程内部所有线程共享整个进程地址空间
线程也是一个动态概念:
线程(进程)状态图
就绪态: ready
运行态: running
阻塞态: blocking
有了线程的概念之后
系统的调度单位就从进程变为线程,资源的分配还是以进程为单位

线程是进程内部的一个指令的执行分支,多个线程就是多个指令序列的并发执行。这些指令必须在函数内部,线程的指令部分肯定是封装一个函数的内部的。这个函数,就称之为:线程函数。
一个线程在创建之后,要执行的指令全部封装在该函数内部,这个线程函数执行完毕之后,该线程的任务也就执行完 了。

线程函数的原型

typedef void *(*start_routine_t)(void *);
// 函数指针:指向一个返回值为void*且带有一个void*参数的函数
//如;
void *my_thread(void *) // 咱自定义的线程函数:必须要符合返回值是void*且带有void*参数的一
个函数
{
// 执行线程需要执行的代码
}

Thread 的实现有多种,比较常见的为 POSIX 线程: pthread

Linux对于pthread的API的支持

pthread_create :创建一个线程(启动一个线程)

PTHREAD_CREATE(3) Linux Programmer's Manual
PTHREAD_CREATE(3)
NAME
pthread_create - create a new thread
SYNOPSIS
#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:线程函数,表示线程启动之后第一时间会执行的函数。 也就是说新线程创建之后会指向start_routine函数内任务。
@arg:参数,表示新线程要去start_routine执行任务,但是start_routine是一个函数。start_routine是函数就可以有参数。所有agr实际上就是传给start_routine的参数的。
@return:成功返回0,失败返回-1,同时errno被设置。

代码举例:

#include <iostream>
#include <pthread.h>
#include <unistd.h>


static int st_val = 0;

/*
    线程函数:用于新线程创建之后调用的
*/
void *new_thread(void *data)
{
    for(;st_val < 20;st_val++)
    {
        sleep(1);
    }

    st_val = 0;
    pthread_exit(&st_val);
}


int main(int argc,const char *argv[])
{
    // 定义线程id的变量
    pthread_t tid;
        
    // 创建线程
    int ret = pthread_create(&tid,NULL,new_thread,NULL);
    if(ret == -1)
    {
        perror("线程创建失败:");
        return -1;
    }

    // 等待子线程把st_val累加到20
    while(1)
    {
        if(st_val >= 20)
            break;
        std::cout << "st_val:" << st_val << std::endl;
        sleep(1);
    }

    return 0;
}

正常退出:线程函数的退出(线程函数的返回)
手动退出:在线程执行的任意时刻调用 pthread_exit

PTHREAD_EXIT(3) Linux Programmer's
Manual PTHREAD_EXIT(3)
NAME
pthread_exit - terminate calling thread
SYNOPSIS
#include <pthread.h>
void pthread_exit(void *retval);
/*
@描述
立即结束线程
@retval:
线程结束之后需要返回的参数,返回值的指针。
*/

被别人干掉
cancel :被别人取消(其他线程调用 pthread_cancel )
t1:pthread_cancel(t2)
t1 调用取消函数,取消 t2 , t2 不一定会被取消
因为 t2 能不能被其他线程取消,取决于 t2 线程的一个属性: 取消属性

NAME
pthread_cancel - send a cancellation request to a thread
SYNOPSIS
#include <pthread.h>
int pthread_cancel(pthread_t thread);
/*
@描述:
取消一个指定的线程
@thread:
线程号,需要取消的那个线程的id号
@return:
成功返回0,失败返回非0.
*/

代码举例:

#include <iostream>
#include <pthread.h>
#include <unistd.h>



static int st_val = 0;

/*
    线程函数:用于新线程创建之后调用的
*/
void *new_thread(void *data)
{
    int oldstate;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&oldstate);

    for(;st_val < 20;st_val++)
    {
        sleep(1);
    }

    st_val = 0;
}

int main(int argc,const char *argv[])
{
        
    // 定义线程id的变量
    pthread_t tid;
        
    // 创建线程
    int ret = pthread_create(&tid,NULL,new_thread,NULL);
    if(ret == -1)
    {
        perror("线程创建失败:");
        return -1;
    }

    // 等待子线程把st_val累加到20
    while(1)
    {
        if(st_val >= 20)
            break;
        std::cout << "st_val:" << st_val << std::endl;

        if(st_val == 5)
        {
            pthread_cancel(tid);
            break;
        }

        sleep(1);
    }
    return 0;
}

SYNOPSIS
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
/*
@描述:
设置线程取消属性的
@state:
设置线程的取消状态
PTHREAD_CANCEL_ENABLE:表示该线程可以被取消
PTHREAD_CANCEL_DISABLE:表示该线程不能被取消
@oldstate:
线程上一次的取消状态
@return:
成功返回0,失败返回其他值
*/

> 一个线程退出了,并不是所有资源都会释放。一个线程的退出,它资源释放全部被释放,取决于一个属性。

ENABLE : 分离资源属性
该线程结束,它的所有资源都会自动释放。
DISABLE : 不分离资源
该线程结束,会有部分资源不会自动释放,需要其他线程调用 pthread_join 这个函数才能完全释放

> 默认是不分离属性。所以要想回收所有资源,就要调用下面这个函数

NAME
pthread_join - join with a terminated thread
SYNOPSIS
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
/*
@描述:
等待一个指定的线程结束 阻塞状态
@thread:
需要等待的线程id号
@retval:
二级指针,表示线程函数的返回值指针
@return:
成功返回0
失败返回-1
*/

当然也能设置函数的分离属性:

NAME
pthread_detach - detach a thread
SYNOPSIS
#include <pthread.h>
int pthread_detach(pthread_t thread);
/*
@描述:
设置线程的资源分离属性
@thread:
需要设置资源分离属性的那个线程id
@return:
成功返回0
失败返回-1
*/

代码举例:

#include <iostream>
#include <pthread.h>
#include <unistd.h>

static int st_val = 0;

/*
    线程函数:用于新线程创建之后调用的
*/
void *new_thread(void *data)
{
    // 进入线程函数第一时间就设置分离属性
    // pthread_detach(pthread_self()); // 设置了资源分离一般就不需要join了

    for(;st_val < 20;st_val++)
    {
        sleep(1);
    }

    st_val = 0;
    pthread_exit(&st_val);
}

int main(int argc,const char *argv[])
{
    // 定义线程id的变量
    pthread_t tid;
        
    // 创建线程
    int ret = pthread_create(&tid,NULL,new_thread,NULL);
    if(ret == -1)
    {
        perror("线程创建失败:");
        return -1;
    }    

    std::cout << "等待线程结束"<< std::endl;
    int *tid_ret_val = NULL;
    pthread_join(tid,(void**)tid_ret_val);

    std::cout << "return value :" << *tid_ret_val << std::endl;
    return 0;
}

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值