Linux下进程和线程的概念

什么是进程

承担分配系统资源的一个基本实体。(至少一个执行流)
它包括独立的地址空间、资源以及1个或多个线程。

什么是线程

线程可以看做是轻量级的进程,是CPU调度和分派的基本单位。


Linux下的进程称为轻量级的进程;
线程出错,相当于进程出错;
一个进程挂掉,不会影响别的进程,进程具有独立性;
线程更高效,进程更安全;


线程的私有数据

一组寄存器;(存放硬件上下文) ❤
栈;(私有栈)❤
线程ID;
errno;
信号屏蔽字;
调度优先级;

注:❤代表重要;

进程线程的共享资源

同一地址空间;
文件描述符表;
每种信号的处理方式;
当前的工作目录;
用户id和组id;


线程与进程的区别

  1. 调度:从上面的定义可以看出一个是调度和分派的基本单位,一个是拥有资源的基本单位;

  2. 共享地址空间,资源:进程拥有各自独立的地址空间,资源,所以共享复杂,需要用IPC,同步简单; 线程共享所属进程的资源,共享简单,但同步复杂,要通过加锁等措施;

  3. 占用内存,cpu: 进程占用内存多,切换复杂,CPU利用率低; 线程占用内存少,切换简单,CPU利用率高;

  4. 相互影响: 进程间不会相互影响; 一个线程挂掉会导致整个进程挂掉。

  1. 地址空间:进程间相互独立,每个进程都有自己独立的地址空间,同一进程的各线程间共享地址空间。某个进程内的线程在其他进程内不可见。
  2. 通信关系:进程间通信有管道,消息队列,共享内存,信号量。线程间通信可以直接读写全局变量来进行通信。不管是进程还是线程,通信时可能出现数据不一致的情况,需要用同步互斥机制来保证数据的一致性
  3. 切换和调度:由于进程间独占数据段代码段等信息,所以切换进程的时候,需要把进程间独占的资源切换去,把要执行的进程资源换进来,而线程是进程的子集,共享大部分资源,切换时只需要保存上下文相关信息就好,所以线程切换的开销比进程切换的开销小。

线程的三种状态

线程主要有三种状态分别是就绪、阻塞、运行。

就绪:线程具备运行的所有条件,逻辑上已可以运行,在等待处理机。

阻塞:指线程在等待某一时间的发生,如I/O操作。

运行:占有处理器正在运行。

线程控制

主要学习线程的创建、终止、等待以及获取线程的运行结果,判断线程是否异常退出,线程生命结束时有没有“遗言”。

###创建线程

#include <pthread.h>

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

描述:创建一个线程,用第一个参数线程标识符,第二个参数设置线程属性,第三个参数指定线程函数运行的起始地址(函数指针),第四个参数是运行函数的参数。

实例:下面的代码创建了两个线程,并分别在线程中调用pthread_self()打印各自的线程ID,以及调用 getpid() 打印进程ID,为了对比也在创建线程的Main执行流中打印线程ID,和进程ID。

#include <stdio.h>
#include <pthread.h>    // pthread_create()
#include <unistd.h>     // sleep()
#include <sys/types.h>  // getpid()

// 打印每个线程的ID, 和进行ID

void * run_1(void *arg)  // 线程1 执行代码
{
    sleep(1);
    printf(" thread 1 tid is  %u,  pid is %u \n", pthread_self(), getpid()); 
}

void * run_2(void *arg)  // 线程2 执行代码
{

    sleep(1);
    printf(" thread 2 tid is  %u,  pid is %u \n", pthread_self(), getpid());
}

int main()
{
    pthread_t tid1, tid2;

    pthread_create(&tid1, NULL, run_1, NULL ); // 创建线程1
    pthread_create(&tid2, NULL, run_2, NULL ); // 创建线程2

    sleep(2);
    printf("I am main tid is  %u,  pid is %u \n", pthread_self(), getpid());
    return 0;
}

这里写图片描述

从上图执行结果以及对代码的分析可以得出:

1).线程1 和线程2 的进程ID一样,可以说明同一个进程可以拥有多个线程,即多个执行流。

2 ) .我们发现在main 执行流中打印线程ID ,与创建的线程差异并不大,也就是说main 执行流也是一个线程。也可以这样理解:在Linux中,一个进程默认有一个线程。单线程也就是单进程。

3 ).在代码中之所以要在main 的执行流中sleep(2),是因为线程执行顺序与操作系统的调度算法有关系,为了保证创建的线程1 和线程2 先执行,故在 main的打印之前加上sleep(2)。

4 ).在线程1 和线程2 的执行代码中都是一开始就sleep(1),而我们在main中创建线程的时候却是先创建的线程1,但是打印结果却是,线程2 先打印,这进一步证实了 3) 中所说,同一个进程中哪一个线程先执行与操作系统调度有关。

5 ). 有一点需要强调,当main 结束的时候,运行到return,或者调用exit(),所有线程也会随之结束,下面的小程序证明这点。

#include <stdio.h>
#include <unistd.h> // sleep()
#include <pthread.h>
#include <stdlib.h> // exit()

void *run( void * arg)
{
    while(1)
    {
        printf("I am still alive ... \n");
        sleep(1);
    }
}

int main()
{
    pthread_t tid1;
    pthread_create(&tid1, NULL, run, NULL);

    sleep(2);
    printf(" The main thread ends and all threads end.\n");
    exit(0); // main thread quit

    return 0;
}

执行结果:新线程每隔1秒打印一次,主线程在2秒后exit,新线程也随之结束。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_38682277/article/details/79904210