-
2020-05-10 09:44:23
FreeRTOS里面没有任务和线程的概念!在FreeRTOS中任务、线程、进程这三者通通都是同一个东西。
我觉得是不是学了linux系统编程之后再去看freertos就会很轻松?再去弄其他操作系统的编程可能就大同小异。
更多相关内容 -
任务、进程、线程之间的区别
2017-08-15 08:41:46一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现...任务 (task)是最抽象的,是一个一般性的术语,指由软件完成的一个活动。一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现。进程 (process)常常被定义为程序的执行。可以把一个进程看成是一个独立的程序,在内存中有其完备的数据空间和代码空间。一个进程所拥有的数据和变量只属于它自己。线程 (tread)则是某一进程中一路单独运行的程序。也就是说,线程存在于进程之中。一个进程由一个或多个线程构成,各线程共享相同的代码和全局数据 ,但各有其自己的堆栈。由于堆栈是每个线程一个,所以局部变量对每一线程来说是私有的 。由于所有线程共享同样的代码和全局数据,它们比进程更紧密,比单独的进程间更趋向于相互作用,线程间的相互作用更容易些,因为它们本身就有某些供通信用的共享内存:进程的全局数据。一个进程和一个线程最显著的区别是:线程有自己的全局数据。线程存在于进程中,因此一个进程的全局变量由所有的线程共享。由于线程共享同样的系统区域, 操作系统 分配给一个进程的资源对该进程的所有线程都是可用的,正如全局数据可供所有线程使用一样
进程概念进程是表示资源分配的基本单位,又是调度运行的基本单位。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。所以,进程是系统中的并发执行的单位。在Mac、Windows NT等采用微内核结构的操作系统中,进程的功能发生了变化:它只是资源分配的单位,而不再是调度运行的单位。在微内核系统中,真正调度运行的基本单位是线程。因此,实现并发功能的单位是线程。线程概念线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如, 假设用户启动了一个窗口中的 数据库 应用程序,操作系统就将对数据库的调用表示为一个进程。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。 线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行。操作系统提供线程就是为了方便而有效地实现这种并发性引入线程的好处(1)易于调度。(2)提高并发性。通过线程可方便有效地 实现并发性。进程可创建多个线程来执行同一程序的不同部分。(3)开销少。创建线程比创建进程要快,所需开销很少。。(4)利于充分发挥多处理器的功能。通过创建多线程进程(即一个进程可具有两个或更多个线程),每个线程在一个处理器上运行,从而实现应用程序的并发性,使每个处理器都得到充分运行。进程和线程的关系(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。(3)处理机分给线程,即真正在处理机上运行的是线程。(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。 -
Linux -- 多任务机制(任务、进程、线程)介绍
2021-10-18 17:40:01多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务。 Linux就是一个支持多任务的操作系统,多任务操作系统使用...多任务操作系统中通常有3个基本概念:任务、进程、线程。Linux -- 多任务机制(任务、进程、线程)介绍内容概要
不管是在平平常常的工作中,还是在激动人心的面试中,都会或多或少、或深或浅的涉及到进程和线程相关的问题,作为常在河边走彳亍的人来说,再被问到关于进程和线程较为深入的问题的时候,虽然表面上稳如老狗,但是心里难免慌得一批。所以,为了不争馒头争口气,从今以后好好再学习一下关于进程和线程的东西,争取心里和面上都能够稳如老狗。
摘要
多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务。 Linux就是一个支持多任务的操作系统,多任务操作系统使用某种调度策略支持多个任务并发执行。事实上。(单核)处理器在某一时刻只能执行一个任务。每个任务创建时被分配时间片(几十到上百毫秒),任务执行(占用CPU)时,时间片递减,操作系统会在当前任务的时间片用完时调度执行其他任务。由于任务会频繁地切换执行,因此给用户多个任务同时运行的感觉。
多任务操作系统中通常有三个基本概念:任务、进程、线程。下面进行一一说明。
一、任务
任务 是一个逻辑概念,指由一个软件完成的活动,或者是为实现个目的的一系列操作。通常一个任务是一个程序的一次运行,一个任务包含一个或多个完成独立功能的子任务,这个独立的子任务是 进程 或者是 线程。
任务、进程和线程之间的关系如图3.1所示。
图3.1 任务、进程和线程之间的关系 二、进程和程序的区别
程序 是一段静态的代码,是保存在非易失性存储器上的指令和数据的有序集合,没有任何执行的概念;
进程 是一个动态的概念,它是程序的一次执行过程,包括了 动态创建、调度、执行和消亡 的整个过程,进程是一个 独立的可调度的任务,它是 程序执行和资源管理的最小单位;
进程 是一个抽象实体。当系统在执行某个程序时,分配和释放的各种资源;
进程 是一个程序的一次执行的过程 。
从操作系统的角度看,进程 是 程序 执行时相关资源的总称。当进程结束时,所有资源被操系统自动回收。
三、进程
3.1、进程的基本概念
进程 是指 一个具有独立功能的程序在某个数据集合上的一次动态执行过程。
它是操作系统 进行资源分配和调度的基本单元。一次任务的运行可以激活多个进程,这些进程相互合作来完成该任务的一个最终目标。
3.2、进程的主要特性
1、并发性。指的是系统中多个进程可以同时并发执行,相互之间不受干扰;
2、动态性。指的是进程都有完整的生命周期,而且在进程的生命周期内,进程的状态是不断变化的,另外,进程具有动态的地址空间(包括代码、数据和进程控制块等);
3、交互性。指的是进程在执行过程中可能会与其他进程发生直接和间接的通信,如进程同步和进程互斥等,需要为此添加一定的进程处理机制;
4、独立性。指的是进程是一个相对完整的资源分配和调度的基本单位,各个进程的地址空间是相互独立的,只有采用某些特定的通信机制才能实现进程之间的通信。3.3、Linux 系统中进程的类型
1、交互式进程。此类进程经常与用户进行交互,需要等待用户的输入(键盘和鼠标操作等)。当接收到用户的输入之后,这类进程能够立刻响应。
典型的交互式进程有shell命令进程、文本编辑器和图形应用程序运行等。
2、批处理进程。此类进程不必与用户进行交互,因此通常在后台运行。因为这类进程通常不必很快地响应,因此往往不会优先调度。
典型的批处理进程是编译器的编译操作、数据库搜索引擎等。
3、守护进程。这类进程一直在后台运行,和任何终端都不关联。通常系统启动时开始执行,系统关闭时才结束。很多系统进程(各种服务)都是以守护进程的形式存在。
3.4、Linux下的进程结构
进程 包括程序的指令和数据,也包括程序计数器和处理器的所有寄存器以及存储临时数据的进程堆栈。
因为Linux是一个多任务的操作系统,所以其他的进程必须等到操作系统将处理器使用权分配给自己之后才能运行。当正在运行的进程需要等待其他的系统资源时,Linux内核将取得处理器的控制权,按照某种调度算法将处理器分配给某个正在等待执行的进程。内核将所有的进程存放在双向链表(进程链表)中,链表的每一项都是 task_struct,称为 进程控制块的结构,该结构包含了与一个 进程相关的所有信息,在
<include/Linux/sched.h>
文件中定义。task_struct 内核结构比较大,它能完整地描述一个进程,如 进程的状态、进程的基本信息、进程标识符、内存相关信息、父进程相关信息、与进程相关的终端信息,当前工作目录,打开的文件信息、所接收的信号信息等。task_struct结构体定义如下所示。
struct task_struct { /* * offsets of these are hardcoded elsewhere - touch with care */ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ unsigned long flags; /* per process flags, defined below */ int sigpending; mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ struct exec_domain *exec_domain; volatile long need_resched; unsigned long ptrace; int lock_depth; /* Lock depth */ /* * offset 32 begins here on 32-bit platforms. We keep * all fields in a single cacheline that are needed for * the goodness() loop in schedule(). */ long counter; long nice; unsigned long policy; struct mm_struct *mm; int has_cpu, processor; unsigned long cpus_allowed; /* * (only the 'next' pointer fits into the cacheline, but * that's just fine.) */ struct list_head run_list; unsigned long sleep_time; struct task_struct *next_task, *prev_task; struct mm_struct *active_mm; /* task state */ struct linux_binfmt *binfmt; int exit_code, exit_signal; int pdeath_signal; /* The signal sent when the parent dies */ /* ??? */ unsigned long personality; int dumpable:1; int did_exec:1; pid_t pid; pid_t pgrp; pid_t tty_old_pgrp; pid_t session; pid_t tgid; /* boolean value for session group leader */ int leader; /* * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with * p->p_pptr->pid) */ struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr; struct list_head thread_group; /* PID hash table linkage. */ struct task_struct *pidhash_next; struct task_struct **pidhash_pprev; wait_queue_head_t wait_chldexit; /* for wait4() */ struct semaphore *vfork_sem; /* for vfork() */ unsigned long rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; struct timer_list real_timer; struct tms times; unsigned long start_time; long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; int swappable:1; /* process credentials */ uid_t uid,euid,suid,fsuid; gid_t gid,egid,sgid,fsgid; int ngroups; gid_t groups[NGROUPS]; kernel_cap_t cap_effective, cap_inheritable, cap_permitted; int keep_capabilities:1; struct user_struct *user; /* limits */ struct rlimit rlim[RLIM_NLIMITS]; unsigned short used_math; char comm[16]; /* file system info */ int link_count; struct tty_struct *tty; /* NULL if no tty */ unsigned int locks; /* How many file locks are being held */ /* ipc stuff */ struct sem_undo *semundo; struct sem_queue *semsleeping; /* CPU-specific state of this task */ struct thread_struct thread; /* filesystem information */ struct fs_struct *fs; /* open file information */ struct files_struct *files; /* signal handlers */ spinlock_t sigmask_lock; /* Protects signal and blocked */ struct signal_struct *sig; sigset_t blocked; struct sigpending pending; unsigned long sas_ss_sp; size_t sas_ss_size; int (*notifier)(void *priv); void *notifier_data; sigset_t *notifier_mask; /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; /* Protection of (de-)allocation: mm, files, fs, tty */ spinlock_t alloc_lock; };
下面详细讲解 task_struct 结构中最为重要的两个域:state(进程状态)和 pid(进程标识符)。
volatile long state; pid_t pid;
其他想要详细了解 task_struct 结构体的其他成员,可以参考大佬文章:
https://tanglinux.blog.csdn.net/article/details/7292563
https://tanglinux.blog.csdn.net/article/details/73351873.5、Linux下的进程主要状态
1、运行状态(TASK_RUNNING)。进程当前正在运行,或者正在运行队列中等待调度。
2、可中断的阻塞状态(TASK_INTERRUPTIBLE)。进程处于阻塞(睡眠)状态,正在等待某些事件发生或能够占用某些共用资源。处在这种状态下的进程可以被信号中断。接收到信号或被显式地唤醒呼叫(如调用 wake_up 系列宏:wake_up、wake_up_interruptible 等)唤醒之后,进程将转变为 TASK_RUNNING 状态。
3、不可中断的阻塞状态(TASK_UNINTERRUPTIBLE)。此进程状态类似于可中断的阻塞状态(TASK_INTERRUPTIBLE),只是它不会处理信号,把信号传递到这种状态下的进程不能改变它的状态。在一些特定的情况下(进程必须等待,直到某些不能被中断的事件发生),这种状态是很有用的。只有在它所等待的事件发生时,进程才被显式地唤醒呼叫唤醒。
4、暂停状态(TASK_STOPPED)。进程的执行被暂停,当进程收到 SIGSTOP、SIGTSTP、SIGTTIN、SIGTTOU 等信号,就会进入暂停状态。
5、僵死状态(EXIT_ZOMBIE)。子进程运行结束,父进程未退出,并且未使用 wait 函数族(比如使用 wait、waitpid 等函数)等系统调用来回收子进程的退出状态。处在该状态下的子进程已经放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其父进程收集。
6、消亡状态(EXIT_DEAD)。这是最终状态,父进程用 wait 函数族回收之后,子进程彻底由系统删除,不可见。
进程各个状态之间的转换关系如图3.2所示。
图3.2 进程各个状态之间的转换关系图
内核可以使用
set_task_state
和set_current_state
宏来改变指定进程的状态和当前执行进程的状态。
set_task_state
宏定义如下所示。#define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) #ifdef CONFIG_SMP #define set_task_state(tsk, state_value) \ set_mb((tsk)->state, (state_value)) #else #define set_task_state(tsk, state_value) \ __set_task_state((tsk), (state_value)) #endif
set_current_state
宏定义如下所示。#define __set_current_state(state_value) \ do { current->state = (state_value); } while (0) #ifdef CONFIG_SMP #define set_current_state(state_value) \ set_mb(current->state, (state_value)) #else #define set_current_state(state_value) \ __set_current_state(state_value) #endif
3.6、Linux下的进程的标识符
Linux 内核通过唯一的进程标识符 PID 来标识每个进程,虽然是唯一的,但是z合格进程 ID 是可以复用的。但一个进程终止后,其进程 ID 就成为复用的候选者。
此进程标识符定义在task_struct 结构体中
pit_d pid
。系统中可以创建的进程数目有限制,可以通过指令/proc/sys/kernel/pid_max
来确定进程上限。比如在 Ubunu 20.14 LTS 下此上限为 32768。
$ cat /proc/sys/kernel/pid_max 32768
当系统启动后,内核通常作为某一个进程的代表。一个指向
task_struct
的宏 current 用来记录正在运行的进程。 current 经常作为 进程描述符结构指针 的形式出现在内核代码中,例如,current->pid
表示 处理器正在执行的进程的PID,当系统需要查看所有的进程时,则调用for_each_process()
宏,这将比系统搜索数组的速度要快得多。在 Linux 中可以通过函数
getpid()
和getppid()
来获取当前进程的进程号( PID )和父进程号(PPID )。getpid()
和getppid()
函数原型如下所示。#include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getppid(void);
3.7、进程的创建、执行和终止
1、进程的创建和执行
许多操作系统都提供产生进程的机制,也就是首先在新的地址空间里创建进程、读入可执行文件,最后再开始执行。
Linux 中进程的创建很特别,它把上述步骤分解到两个单独的函数中执行:
fork()
和exec
函数族。
首先,fork()
通过 复制当前进程创建一个子进程,子进程 与 父进程 的区别仅在于不同的 PID、 PPID 和某些资源及统计量。exec
函数族负责 读取可执行文件 并将其 载入地址空间开始运行。fork()
函数的原型如下所示:#include <unistd.h> pid_t fork(void);
返回值说明:
若函数执行正确,则子进程返回为0,父进程返回子进程ID
若函数出错,则返回-1要注意的是,Linux 中的
fork()
使用的是 写时复制( copy on write )的技术,也就是内核在创建进程时,其资源并没有立期被复制过来,而是被推迟到需要写入数据的时候才发生。在此之前只是以只读的方式共享父进程的资源。写时复制技术可以使Linux 拥有快速执行的能力。2、进程的终止
进程终止也需要做很多烦琐的收尾工作,系统必须保证进程所占用的资源回收,并通知父进程。
Linux 首先把终止的进程设置为 僵死状态。这个时候,进程已经无法运行,它的存在只为父进程提供信息。父进程在某个时间调用wait函数族,回收子进程的退出状态,随后子进程占用的所有资源被释放。
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *wstatus); pid_t waitpid(pid_t pid, int *wstatus, int options);
返回值说明:
如果函数成功,返回进程ID
如果函数出错,返回 -1进程的终止有5 种正常终止和3 种异常终止,下面分别进行简单的说明。
5种正常终止的情况如下所示。1、在 main 函数中执行 return 语句;
2、调用 exit 函数;
3、调用 _exit 函数或者 _Exit() 函数;
4、进程的最后一个线程在其启动例程中执行 return 语句;
5、进程的最后一个线程调用 pthread_exit 函数。3种异常的终止情况如下所示。
1、调用 abort ;
2、当进程接收到某些信号;
3、最后一个线程对“取消”请求作出响应。
关于exit()、_exit()、return等详细说明,可以查看博文:
https://songshuai0223.blog.csdn.net/article/details/120850739关于多进程的编程与实现,可以查看博文:
https://songshuai0223.blog.csdn.net/article/details/1209401423.8、进程的内存结构
Linux 操作系统来用虚拟内存管理技术,使得每个进程都有独立的地址空间。该地址空间是大小为 4GB 的线性虚拟空间,用户所看到和接触到的都是该虚拟地址,无法看到实际的物理内存地址。利用这种虚拟地址不但更安全(用户不能直接访问物理内存),而且用户程序可以使用比实际物理内存更大的地址空间。
4GB 的进程地址空间会被升成两个部分:用户空间 与 内核空间。用户地址空间是 0 - 3GB(0 – 0xC0000000 ),内核地址空间占据 3 - 4GB 的空间位置,用户进程在通常情况下只能访问用户空间的虚拟地址,不能访问内核空间虚拟地址。只有用户进程使用系统调用(代表用户进程在内核态执行)时才可以访问到内核空间。每当进程切换,用户空间就会跟者变化;而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核空间地址有自己对应的页表,用户进程各自有不同的页表。每个进程的用户空间都是完全独立、互不相干的。
进程的虚拟内存地址空间如图3.3所示。
图3.3 进程地址空间的分布图
用户空间包括以下几个功能区域(通常也称之为 “段(segment”)。
1、 只读段。具有只读属性,包含程序代码(.init、text )和只读数据(.rodata)。
2、 数据段。存放的是全局变量和静态变量。其中初始化数据段(.data)存放 显式初始化的全局变量和静态变量;未初始化数据段,此段通常被称为BSS段(.bss),存放未进行显式初始化的全局变量和静态变量。3、 栈。由系统自动分配释放,存放函数的参数值、局部变量的值、返回地址等。
4、 堆。存放动态分配的数据,一般由程序员动态分配和释放,若程序员不释放,程序结束时可能由操作系统回收。
5、 共享库的内存映射区域。这是 Linux 动态链接器和其他共享库代码的映射区域。因为在 Linux 系统中每一个进程都会有 /proc 文件系统下的与之对应的一个目录(比如,init 进程的相关信息存放在/proc/1 目录下),因此通过 proc 文件系统可以查看某个进程的地址空间的映射情况。例如,运行一个应用程序,如果他的进程号为13703,则输入
cat/proc/13703/maps
命令,可以查看该进程的内存映射情况。$ cat /prac/13703/maps /* 只读段:代码段、只读数据段 */ 00400000-004f4000 r-xp 00000000 08:01 1594825 /bin/bash 006f3000-006f4000 r--p 000f3000 08:01 1594825 /bin/bash /* 可读可写数据段 */ 006f4000-006fd000 rw-p 000f4000 08:01 1594825 /bin/bash 006fd000-00703000 rw-p 00000000 00:00 0 /* 可读可读段 -- 堆 */ 01d7f000-01f4c000 rw-p 00000000 00:00 0 [heap] /* 动态共享库 */ 7f7717f40000-7f7717f4b000 r-xp 00000000 08:01 4467304 /lib/x86_64-linux-gnu/libnss_files-2.23.so /* 省略部分内容 */ ... /* 可读可写数据区 */ 7f7719629000-7f771962a000 rw-p 00000000 00:00 0 /* 堆栈 */ 7ffdb411e000-7ffdb413f000 rw-p 00000000 00:00 0 [stack] 7ffdb41da000-7ffdb41dd000 r--p 00000000 00:00 0 [vvar] 7ffdb41dd000-7ffdb41df000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
四、线程
4.1、线程概述
众所周知,进程是系统中程序执行和资源分配的基本单位。每个进程都拥有自己的数据段、代码段和堆栈段,这就造成了进程在进行切换时操作系统的开销比较大。
所以,为了提高效率, 操作系统又引入了 线程 概念,也称为 轻量级进程。线程可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享。因此, 线程的上下文切换的开销比进程小得多。
另外,一个进程可以拥有多个线程,其中每个线程共享该进程所拥有的资源。要注意的是,由于线程共享了进程的资源和地址空间,因此,任何线程对系统资源的操作都会给其他线程带来影响。所以,多线程中同步是非常关键的问题。
进程和线程之间的关系如图3.4所示。
图3.4 进程和线程之间的关系
4.2、线程标识
每个线程都包含有表示执行环境所必需的信息,其中包括进程中标识线程的线程ID、一组寄存器、栈、调度优先级和策略、信号屏蔽字、errno标量、线程私有数据等。一个进程的所有信息对该进程的所有线程是共享的,包括可执行程序的代码、程序的全局内存和堆内存、栈、文件描述符。
线程也有一个线程ID(Linux环境下,线程ID是用无符号长整形来表示的),与进程ID不同的是,线程ID只有在它所属的进程上下文才有意义。
线程可以通过调用函数
pthread_self()
来获取自身的线程ID。#include <pthread.h> pthread_t pthread_self(void); 返回值:调用线程的线程ID
4.3、线程的创建和终止
1、线程的创建
新增线程可以通过调用函数
pthread_create()
来实现。#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
2、线程的终止
如果进程中任意线程调用了exit()、_Exit()、_exit()等 ,那么整个进程就会终止,与此类似,如果默认的动作是终止进程,那么发送到线程的信号就会终止整个进程。
单个线程可以有3种方式退出,因此在不终止整个进程的情况下,停止它的控制流。
1、线程可以简单地从启动例程中返回,返回值线程的退出码;
2、线程可以被同一进程中的其他线程取消;
3、线程调用pthread_exit()函数。线程可以通过调用
pthread_cancel()
函数来取消同一进程中的其他线程。#include <pthread.h> int pthread_cancel(pthread_t thread);
线程可以通过调用
pthread_exit()
函数来取消线程。#include <pthread.h> void pthread_exit(void *retval);
关于多线程的编程与实现,可以查看博文:
https://songshuai0223.blog.csdn.net/article/details/120830985五、进程和线程的区别
1、基本区别:进程是资源分配最小单位,线程是程序执行的最小单位;
2、空间关系:同一进程的各个线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的;
3、所属关系:线程是进程的一部分,进程中可以包含很多个线程(进程中至少有一个线程,称为主线程),线程也称为轻量级进程;
4、影响关系:进程相互独立(独立的地址空间),所以一个进程崩溃后,一般不会对其他进程产生影响,但是一个线程(共享地址空间)崩溃整个进程都异常崩溃;
5、通信关系:同一个进程下,线程共享全局变量,静态变量等数据,所以线程之间的通讯简单,但是存在同步与互斥的难点,进程之间的通信需要以通信的方式(IPC)进行;
6、开销方面:每个进程都有独立的代码和数据空间(程序上下文),进程之间切换开销大;线程之间共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小;
7、资源方面:进程对资源保护要求高,开销大,效率相对较低,线程资源保护要求不高,但开销小,效率高,可频繁切换;
8、 环境关系:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行;
9、执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,进程和线程都可以并发执行。
好啦,废话不多说,总结写作不易,如果你喜欢这篇文章或者对你有用,请动动你发财的小手手帮忙点个赞,当然 关注一波 那就更好了,就到这儿了,么么哒(*  ̄3)(ε ̄ *)。上一篇:本文
下一篇:Linux – 多进程的编程之 - 基础实现、孤儿进程 -
进程和线程的区别(超详细)
2019-10-03 21:57:46进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。 与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有...文章目录
进程和线程
进程
一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。
线程
进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
Java 程序天生就是多线程程序,我们可以通过 JMX 来看一下一个普通的 Java 程序有哪些线程,代码如下。
public class MultiThread { public static void main(String[] args) { // 获取 Java 线程管理 MXBean ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); // 不需要获取同步的 monitor 和 synchronizer 信息,仅获取线程和线程堆栈信息 ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false); // 遍历线程信息,仅打印线程 ID 和线程名称信息 for (ThreadInfo threadInfo : threadInfos) { System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo.getThreadName()); } } }
上述程序输出如下(输出内容可能不同,不用太纠结下面每个线程的作用,只用知道 main 线程执行 main 方法即可):
[6] Monitor Ctrl-Break //监听线程转储或“线程堆栈跟踪”的线程 [5] Attach Listener //负责接收到外部的命令,而对该命令进行执行的并且把结果返回给发送者 [4] Signal Dispatcher // 分发处理给 JVM 信号的线程 [3] Finalizer //在垃圾收集前,调用对象 finalize 方法的线程 [2] Reference Handler //用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收的线程 [1] main //main 线程,程序入口
从上面的输出内容可以看出:一个 Java 程序的运行是 main 线程和多个其他线程同时运行。
进程与线程的区别总结
线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进程都有若干个线程,至少包含一个线程。
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行
从 JVM 角度说进程和线程之间的关系(重要)
图解进程和线程的关系
下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。
从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的堆和方法区 (JDK1.8 之后的元空间)资源,但是每个线程有自己的程序计数器、虚拟机栈 和 本地方法栈。
程序计数器为什么是私有的?
程序计数器主要有下面两个作用:
- 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
- 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。
所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。
虚拟机栈和本地方法栈为什么是私有的?
- 虚拟机栈:每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
- 本地方法栈:和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。
一句话简单了解堆和方法区
堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
多进程和多线程区别
多进程:操作系统中同时运行的多个程序
多线程:在同一个进程中同时运行的多个任务
举个例子,多线程下载软件,可以同时运行多个线程,但是通过程序运行的结果发现,每一次结果都不一致。 因为多线程存在一个特性:随机性。造成的原因:CPU在瞬间不断切换去处理各个线程而导致的,可以理解成多个线程在抢CPU资源。
多线程提高CPU使用率
多线程并不能提高运行速度,但可以提高运行效率,让CPU的使用率更高。但是如果多线程有安全问题或出现频繁的上下文切换时,运算速度可能反而更低。
Java中的多线程
Java程序的进程里有几个线程:主线程,垃圾回收线程(后台线程)等
在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。
Java支持多线程,当Java程序执行main方法的时候,就是在执行一个名字叫做main的线程,可以在main方法执行时,开启多个线程A,B,C,多个线程 main,A,B,C同时执行,相互抢夺CPU,Thread类是java.lang包下的一个常用类,每一个Thread类的对象,就代表一个处于某种状态的线程
-
程序、任务、进程和线程的联系与区别
2018-04-13 11:03:39一个任务既可以是一个进程,也可以是一个线程。简而言之,它指的是一系列共同达到某一目的的操作。例如,读取数据并将数据放入内存中。这个任务可以作为一个进程来实现,也可以作为一个线程(或作为一个中断任务)来实现... -
什么是多任务?什么叫做进程?什么是线程?
2017-01-24 09:27:571、什么叫做多任务? IT系统,同时完成多项任务处理,这个同时指的是同一段...当多任务操作系统使用某种任务调度策略允许两个或更多进程并发共享一个处理器时,事实上处理器在某一时刻只会给一件任务提供服务。因为 -
什么是进程?什么是线程?进程与线程的区别?如何选择进程或者线程
2020-05-08 14:17:27什么是进程? 什么是线程? 线程和进程之间的区别 进程和线程的选择取决于什么? 计算密集型任务以及I/O密集型任务 在python中,多进程和多线程的选择取决于什么 -
【完全解读】RTOS中的任务是线程?进程?还是协程?
2020-05-19 22:38:543) 线 程 进程的目的是隔离并发,可以说线程是实现的共享并发,所有的线程都是共用属于进程的资源,线程是进程指令流的剥离,同样线程有对应的结构体信息管理TCB类似于RTOS中的TCB。 由于线程资源共享,所以各个... -
什么是进程,什么是线程,多线程与多进程的区别?
2021-03-15 20:35:33什么是进程,什么是线程,多线程与多进程的区别?什么是进程,什么是线程多线程与多进程的区别 什么是进程,什么是线程 什么是进程,什么是线程,以及... 首先明确多进程和多线程都能“同时实现多个任务”。假设要同 -
进程线程(一)——基础知识,什么是进程?什么是线程?
2020-10-10 19:09:311. 什么是进程和线程 现代操作系统比如Mac OS X,UNIX,Linux,Windows等,都是支持“多任务”的操作系统。 1.1 百科解释 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和... -
进程和线程合集以及实例
2020-10-12 11:34:51文章目录进程和线程0.1 粗略介绍:0.2 线程进程区别:一.进程1.1 fork创建单进程1.2 multiprocessing:Process 创建子进程1.2 multiprocessing:Pool 创建进程池1.3 进程间通信 公共队列二. 线程2.1 多线程的优点:二. ... -
python并发技术实现(多线程、多进程)
2018-12-07 01:15:54压缩包内包含四个文件,实现的效果都是通过多线程或多进程执行加法运算; multiprocess_queue,通过任务队列方式实现多进程任务;(multiprocessing模块) multithread_queue,通过任务队列方式实现多线程任务;... -
汽车软件RTOS概念——进程,线程,任务
2020-12-15 22:00:35一般看《计算机操作系统》的书籍,都会有进程(Process),线程(Thread)的概念。但是在嵌入式RTOS里面,比如应用于汽车软件的OSEK/VDX Operating System Specification 2.2.3规范里没有这两个概念,有的是任务... -
进程和线程的分配策略【杂记】
2022-02-08 19:02:33进程和线程的分配策略【杂记】 -
RTOS的Task 是进程还是线程还是协程
2020-06-12 09:41:27好了,今天为大家讲解讲解OS中的线程、进程和协程的这几个概念,同时一起看看RTOS中的任务到底属于哪一种。 先来看看什么概念: 线 程(英语:thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之... -
进程与线程
2021-03-17 22:50:20进程与线程 1 进程 1.1 进程的概念 进程就是正在运行的程序,它代表了程序所占用的内存区域 1.2 进程的特点 独立性 进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有... -
python 多线程实现多任务,多进程实行多任务
2021-07-19 16:23:38目录 1 多线程实现多任务 1.1 什么是线程? 1.2 一个程序实现多任务的方法 1.3多线程的创建方式 ...1.3.1创建threading.Thread对象 ...2多进程实行多任务 2.1多线程的创建方式 2.1.1方式1 2... -
进程、线程及协程的区别
2020-10-21 22:53:06**线程:**线程是进程的一个执行单元,是任务调度和系统执行的基本单位; 二、区别 **1、根本区别:**进程是操作系统资源分配和独立运行的最小单位;线程是任务调度和系统执行的最小单位。 **2、地址空间区别:**每... -
【操作系统】第六话·线程是进程的(宝ᴗ宝)嘛?
2022-03-12 15:23:07线程是进程中的一个实体,是被系统独立调度和分派的基本单位,它不拥有系统资源,只拥有一点运行中必可不少的资源,但它可与同属一个进程的其他线程共享进程的全部资源。 一个线程可以创建和撤销另一个线程,同一... -
进程和线程的深入理解
2019-04-25 00:14:40进程和线程的深入理解,从抽象类比到与原理,阐述了两者的区别 -
线程、进程、多线程、多进程 和 多任务 小结
2019-04-20 11:59:565 线程与进程的关系 6 线程和进程的区别 7 进程的优缺点 7.1 进程的优点 7.2 进程的缺点 8 线程的优缺点 8.1 线程的优点 8.2 线程的缺点 9 多线程的优缺点 9.1 多线程的优点 9.2 多线程的缺点 10多进程的... -
进程和线程的概念、区别及进程线程间通信
2020-08-02 16:24:25进程与线程的概念,以及为什么要有进程线程,其中有什么区别,他们各自又是怎么同步的? 1. 基本概念: 进程是对运行时程序的封装,是系统进行资源调度和分配的的基本单位,实现了操作系统的并发; 线程是进程的子... -
Linux多任务编程(一)---任务、进程、线程
2013-06-08 11:04:36任务、进程、线程分别是什么?它们之间的区别是什么?,从而可以宏观的了解一下这三者,然后再针对每一个仔细的讲解。 什么叫多任务系统?多任务系统指可以同一时间内运行多个应用程序,每个应用程序被称作一个... -
Linux系统中 任务、进程和线程总结
2014-05-09 16:03:52任务、进程和线程基本概念 多任务处理是指用户可以在同一时间内运行多个应用程序,每个正在执行的应用程序被称为一个任务。Linux 就是一个支持多任务的操作系统(Windows也是多任务操作系统),比起单任务系统它的... -
终于把进程和线程学会了
2020-07-24 23:59:36主要有:线程和进程的讲解、Java实战多线程、进程和线程的面试题总结等内容 -
程序,进程,线程的区别和联系
2018-08-26 22:27:18它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消。反映了一个程序在一定的数据集上运行的全部动态过程。 2)进程和程序并不是一一对应的,一个程序执行在不同的数据集上... -
Python中进程和线程的区别详解
2019-03-04 09:30:46先说一下什么是进程,线程 进程:进程时计算机程序一次执行的实例,由 程序段 数据段 PCB组成,是计算机资源分配和调度的基本单位,也是线程的容器 线程:线程也叫作轻量级进程,是程序执行的最小单位,他本身... -
什么是进程?什么是线程?什么是协程?
2019-09-24 14:43:13什么是进程?什么是线程?什么是协程?...在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。 狭义定义:进程是正在运行的程序的实例(an i... -
多任务中 多线程和多进程的区别
2019-04-26 14:22:22多任务中 多线程和多线程的区别 -
C语言多任务,多进程,多线程
2018-04-03 15:44:08Linux就是一种支持多任务的操作系统,它支持多进程、多线程等多任务处理和任务之间的多种通信机制。Linux下多任务机制的介绍多任务处理是指用户在同一时间内运行多个应用程序,每个应用程序被称做一个任务。Linux...