Linux下的多线程概念

线程是进程内部的执行单位,一个线程即使进程内的一个执行流。对于线程,每个系统的实现可能不一样,在Linux中,线程也叫轻量级进程,操作系统没有把线程与进程明显的区分开,它们的数据结构是一样的,都是task_struct。在进程资源分配时,以进程为单位进程分配;而在调度时,则以线程为单位。可以这样理解,代码最初被加载进内存中时,系统会给这些代码分配一系列资源,这样就创建了一个“进程”,而进程内部可能会同时实现不同的功能,这就需要进程内部同时有各不相同的数个执行流在执行,这些执行流就是线程。在我们刚开始学习写代码时,写出的程序基本都只有一个执行流,即所有代码按先后顺序依次执行,我们称为单线程的进程;而有的程序出于某些需要,会有多个执行流,即某些代码可能同时执行,这就是多线程的进程。
在一个单线程进程中,进程的模型是这样的:
这里写图片描述
而多线程进程中,进程的模型是这样的:
这里写图片描述
那么为什么有了进程后还要出现线程呢?这得说说线程的优点:
1、创建一个新线程的代价要比创建一个新进程的代价要小得多。
2、与进程间的切换相比,线程间的切换需要系统做的工作要少很多。
3、线程占用的资源比进程要少很多。
4、能充分利用多处理器的可并行数量。
5、在等待慢速I/O操作结束的同时,程序可以做其他工作。
6、计算密集型应用,为了能在多处理器上运行,将计算分解到多个线程中实现。
7、I/O密集型应用,为了提高性能,将I/O重叠,线程可以同时等待不同的I/O操作。
当然,线程也有缺点:
1、性能损失。
2、健壮性降低。
3、缺乏访问控制。
4、编程难度提高。

线程又分为用户级线程和内核级线程。在一个纯粹的用户级线程中,所有有关线程管理的工作都由应用程序完成,内核完全意识不到用户级线程的存在。任何应用程序都可以用线程库设计成所线程程序,线程库包含了用于创建和销毁线程的代码、在线程间传递消息和数据的代码、调度线程执行的代码和恢复上下文的代码。纯粹的用户级线程有便于调度、切换速度快和跨平台等优点,也有一次只能执行一个用户级线程不能利用多处理技术和一个线程进行系统调用被阻塞则所有线程都会被阻塞的缺点。
在一个纯粹的内核级线程应用中,所有有关线程管理的工作全部由内核完成,应用程序没有进行线程管理的代码,仅有到内核级线程设施的程序编程接口(API)。内核级线程克服了纯粹的用户级线程的缺点,可以利用多处理技术,当一个线程被阻塞时,其他的线程也能被调度。但是内核级线程间切换的开销要远远大于纯粹的用户级线程。现在的很多系统都采用用户级线程和内核级线程组合的方法,在用户空间中进行线程的创建、调度等工作,然后映射到内核级线程上,这样就可以综合用户级线程和内核级线程的优点,进而克服它们的缺点。
Linux使用pthread(POSIX thread)线程库来创建用户级线程。组成一个用户级进程的多个用户级线程被映射到共享同一个组ID的多个Linux内核级进程上。这使得这些进程可以共享文件和内存等资源,这样同一组中的进程切换时不需要切换上下文,这些进程可看作属于同一个进程的线程。Linux中,这种由多个共享同一份资源的轻量级进程所组成的进程称为线程组,执行下面代码创建一个双线程的进程:

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#define _GNU_SOURCE
void *thread_run(void *arg)
{
    while(1);
}
int main(void)
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_run, NULL);
    while(1);

    return 0;
}

执行程序,使用指令 ps -eLf |head -1 && ps -eLf |grep a.out |grep -v grep 来观察:
这里写图片描述
可以看到,两个线程的PID与PPID相同,而线程ID即LWP不同。两个线程中,第一个线程的LWP与线程ID—PID相同,第二个不同。通常将线程ID(LWP)与进程ID(PID)相同的线程称为这个线程组的组长,task_struct的部分代码:

struct task_struct
{
    ...    
    pid_t pid; 
    pid_t tgid;
    ... 
    struct task_struct *group_leader;
    ... 
    struct list_head thread_group;
    ... 
};

这里的pid是线程ID,而tgid,表示Thread Group ID,该值对应用户层面的进程ID。同一个线程组中的线程用双向链表连接。
本文讲了关于线程的基本概念,下篇文章讲述关于线程的创建、终止等操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值