Linux多线程-概念和控制(2)

简介: Linux多线程-概念和控制(2)

二、Linux进程VS线程


1、进程和线程


概念:

进程是资源分配的基本单位


线程是调度的基本单位


线程共享进程数据,但也有线程自己独有的数据:

线程ID


一组寄存器中线程自己的上下文数据



errno


信号屏蔽字(handler方法是共享的)


调度优先级


线程中共享的数据:

代码段和数据段


文件描述符表


每种信号的处理方式


当前工作目录


用户id和组id


注:进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到


进程和线程的关系图:


三、Linux线程控制


1、POSIX线程库


pthread线程库是应用层的原生线程库:

应用层指的是这个线程库并不是系统接口直接提供的,而是由第三方提供的


原生指的是大部分Linux系统都会默认带上该线程库


与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的


要使用这些函数库,要通过引入头文件<pthreaad.h>


链接这些线程函数库时,要使用编译器命令的“-lpthread”选项


错误检查:

传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误


pthreads函数出错时不会设置全局变量errno(而大部分POSIX函数会这样做),而是将错误代码通过返回值返回


pthreads同样也提供了线程内的errno变量,以支持其他使用errno的代码。对于pthreads函数的错误,建议通过返回值来判定,因为读取返回值要比读取线程内的errno变量的开销更小


2、线程创建

pthread_create函数原型:


int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);


解释:

功能:创建一个新的线程


参数:thread:输出型参数,返回获取线程ID;attr:设置线程的属性,attr为NULL表示使用默认属性;start_routine:是个函数地址,线程启动后要执行的函数,该函数返回值为void *,参数为void *;arg:传给线程启动函数的参数


返回值:成功返回0;失败返回错误码


注意:

主线程调用pthread_create函数创建一个新线程,此后新线程就会跑去执行参入的函数,而主线程则继续往下执行


对于执行函数来说,参数和返回值的类型都是void *,void *是一个通用的类型,可以传入或者返回数据和其他类型的指针,从而传入和带出多样的类型和数据


示例:


mypthread.c:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
int val=0;
void* Routine(void* avgs)
{
    while(1)
    {
        printf("I am %s... val:%d\n",(char*)avgs,val);
        sleep(1);
    }
}
int main()
{
    pthread_t tid1,tid2,tid3;
    int ret1=pthread_create(&tid1,NULL,Routine,(void*)"pthread 1");
    if(ret1!=0)
    {
        fprintf(stderr,"pthread_creat:%s\n",strerror(ret1));
        exit(1);
    }
    int ret2=pthread_create(&tid2,NULL,Routine,(void*)"pthread 2");
    if(ret2!=0)
    {
        fprintf(stderr,"pthread_creat:%s\n",strerror(ret2));
        exit(1);
    }
    int ret3=pthread_create(&tid3,NULL,Routine,(void*)"pthread 3");
    if(ret3!=0)
    {
        fprintf(stderr,"pthread_creat:%s\n",strerror(ret3));
        exit(1);
    }
    while(1)
    {
        printf("I am main pthread...val:%d\n",val++);
        sleep(1);
    }
    return 0;
}
Makefile:
mypthread:mypthread.c
    gcc -o  $@ $^ -pthread 
.PHONY:clean
clean:
    rm -f mypthread


image.png



注意:

默认情况下,ps命令不带-L,看到的就是一个个的进程;带-L就可以查看到每个进程内的多个轻量级进程


在Linux中,应用层的线程与内核的LWP是一一对应的,实际上操作系统调度的时候采用的是LWP,而并非PID,只不过我们之前接触到的都是单线程进程,其PID和LWP是相等的


3、线程ID及线程地址空间布局


概念:


pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事


前面讲的线程ID(LWP)属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要一个数值来唯一表示该线程


pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的


在Linux系统层面有LWP与线程对应,但是Linux是用轻量级进程模拟的线程,而对于用户来说,并不会关心底层实现,从用户角度来说,他们也需要知道线程的信息,状态以及操作线程,由此在共享区中还相应的构建了TCB(线程控制块),便于用户操作线程,在用户区进行维护

pthread_ self函数原型:



pthread_t pthread_self(void);


功能:获得线程自身的ID

注:对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址

  • 示图:


注:主线程并不使用动态库里的线程栈,而是使用进程里的栈


相关文章
|
1月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
29 0
Linux C/C++之线程基础
|
1月前
|
Ubuntu Java Linux
Linux操作系统——概念扫盲I
Linux操作系统——概念扫盲I
43 4
|
1月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
2月前
|
数据采集 消息中间件 并行计算
进程、线程与协程:并发执行的三种重要概念与应用
进程、线程与协程:并发执行的三种重要概念与应用
57 0
|
3月前
|
存储 缓存 Linux
在Linux中,文件系统概念是什么?
在Linux中,文件系统概念是什么?
|
3月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
3月前
|
缓存 前端开发 JavaScript
一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
【8月更文挑战第11天】一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
36 0
一篇文章助你搞懂java中的线程概念!纯干货,快收藏!
|
3月前
|
存储 安全 Linux
在Linux中,用户和组的概念是什么?
在Linux中,用户和组的概念是什么?
|
3月前
|
Linux 持续交付 虚拟化
在Linux中,Docker和容器虚拟概念是什么?
在Linux中,Docker和容器虚拟概念是什么?
|
3月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?