进程:
并发运行:并发运行是多个任务被同时发起运行,但同一时刻这些任务只能有一个处于运行状态。这取决于cpu核心和cpu数量
并行运行:指同一时刻,可以有多个任务真正的同时运行。必要条件是多cou核心和多cpu核心的计算环境。
并发程序建议:
- 控制临界区的纯度
- 控制临界区的颗粒
- 减少临界区中代码耗时
- 避免传给你时间持有互斥锁
- 优先使用原子操作而非互斥量
进程的标识:
ID(PID):进程的唯一标识(系统范围内唯一)
PPID(父进程的ID):当前进程的父进程ID
pid:=os.Getpid()
ppid:=os.Getppid()
Go的线程实现模型,有三个必知的核心元素:
M:machine的缩写。一个M代表一个内核线程,或者“工作线程”。
P:processor的缩写。一个P代表执行一个Go代码片段所必需的资源(或称“上下文环境”)。
G:goroutine的缩写。一个G代表一个Go代码片段。前者是对后者的一种封装。
简单来说,一个G的执行需要P和M的支持。一个M在与一个P关联之后,就形成了一个有效的G运行环境(内核线程+上下文环境)。
每个P都会包含一个可运行的G的队列(runq)。该队列中的G会被依次传递给与本地P关联的M,并获得运行时机。
在这里,我把运行当前G的那个M称为“当前M”,并把与当前M关联的那个P称为“本地P”
进程的状态:
- 可运行状态(TASK_RUNNING):将要、立即、或者正在内存中运行。
- 可中断的睡眠状态(TASK_INTERRUPTIBLE):处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。当事件发生时,对应的一个或多个进程就会被唤醒。
- 不可中断的睡眠状态(TASK_UNINTERRUPTIBLE):进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。
- 暂停状态或跟踪状态(TASK_STOPPED or TASK_TRACED):向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号)。(SIGSTOP与SIGKILL信号一样,是非常强制的。不允许用户进程通过signal系列的系统调用重新设置对应的信号处理函数。)</br>
向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。
当进程正在被跟踪时,它处于TASK_TRACED这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在gdb中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于TASK_TRACED状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。 - 僵尸状态(TASK_DEAD - EXIT_ZOMBIE):进程在退出的过程中,处于TASK_DEAD状态。在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。
- 退出状态((TASK_DEAD - EXIT_DEAD):退出状态,进程即将被销毁。
线程:
一个线程可以看做是某个进程的一个控制流,一盒进程至少包含一个线程,因为至少有一个控制流持续运行。因而,一个进程的第一个线程会随着它的启动而被创建。
线程的标识:
线程ID(TID):线程的ID(在系统范围内可能不唯一,在所属进程中唯一(linux中线程id唯一),当线程不存在之后,其线程id可以被其他线程复用)
由系统内核分配和维护,
线程减的控制
- 创建线程
- 终止线程
- 连接已终止的线程
- 分离线程
线程的状态
- 就绪状态(Runnable):线程倍创建出来后就进入就绪状态。此时等待被运行的时机
- 运行状态(Running):一旦线程被运行就切换至运行状态。
- 阻塞状态(Blocked):也叫睡眠状态,线程可能因为某种原因,而被阻塞。(I/O操作,等待未接收的信号,等待获得互斥量。)
- 死亡状态(Dead):也叫终止状态,在当前线程自我终止或者其他线程向当前线程发出取消请求且取消时间已到时,当前线程就会试图进入死亡状态