进程与线程 -- C/C++(一)

简介: 程序概念: 存放在磁盘上的指令和数据的有序集合(文件) 静态的

进程与线程


进程


程序概念:

存放在磁盘上的指令和数据的有序集合(文件)


静态的


进程概念:

执行一个程序所分配的资源的总称


进程就是程序的一次执行过程


动态的,包括创建、调度、执行和消亡


进程包括代码、用户数据和 系统数据(进程控制块、cpu寄存器的值、堆栈)


进程控制块(pcb)

进程标识PID


进程用户


进程状态、优先级


文件描述符表


进程类型

交互进程:在shell下启动。以在前台运行,也可以在后台运行。


批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行。


守护进程:和终端无关,一直在后台运行。


进程状态

运行态:进程正在运行或者准备运行


等待态:进程在等待一个事件的发生或某种系统资源 – 分为可中断和不可中断两种状态


停止态:进程被终止,收到信号后可以继续运行


死亡态:已终止的进程,但是pcb没有被释放(僵尸进程)


查看进程信息

ps 查看系统进程快照 ps -ef | grep ps aux(显示进程当前状态)


top 查看进程动态信息 top


/proc 查看进程详细信息


创建进程 - fork

pid_t fork(void);

以下代码在linux中运行:

#include <unistd.h>
#include <stdio.h>
int main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0)
    {
        perror("fork");
        return -1;
    }
    if(pid == 0)
    {
        printf("child process; my pid is %d\n", getpid());
    }
    else
    {
        printf("parent process; my pid is %d\n", getpid());
    }
}

父子进程:

1.子进程继承了父进程内容


2.父子进程有独立的地址空间,互不影响


3.若父进程先结束


子进程成为孤儿进程,被init(1)进程收养

  ○ 子进程变成后台进程


4.若子进程先结束


 父进程如果没有及时回收,子进程变成僵尸进程


子进程从何处开始运行? 从fork()之后语句开始执行。


父子进程谁先执行? 不确定,由内核调度决定


父进程能否多次调用fork()? 子进程呢? 都可以


结束进程 - exit/_exit

#include <stdlib.h>
#include <unistd.h>
void exit(int status);
void _exit(int status); // 丢弃缓冲区

结束当前进程,并且将status 返回


exit结束进程时会刷新(流)缓冲区


以下代码在linux中运行:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    printf("aaa");
    _exit(0);
    printf("bbbb");
}

exec函数族

调用exec函数族执行某个程序


进程当前内容被指定程序替换


实现让父子进程执行不同的程序


     ● 父进程创建子进程

     ● 子进程调用exec函数族

     ● 父进程不受影响


进程 - execl/execlp

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);

成功时执行置顶程序;失败时候返回EOF


path 执行程序名称,包含路径


arg… 传递给执行程序的参数列表


file 执行程序名称,在PATH中查找

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    if(execl("/bin/ls", "ls", "-al", "/etc", NULL) < 0)
    {
  perror("execl");
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    if(execlp("ls", "ls", "-al", "/etc", NULL) < 0)
    {
      perror("execlp");
    }
}

进程 - execv/execvp

int execv(const char *path,  char *const arg[]);
int execvp(const char *file, char *const arg);

成功时执行置顶程序;失败时候返回EOF


arg… 封装成指针数组的形式

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    char *argv[] = { "ls", "-al", "/etc", NULL};
    if(execv("/bin/ls",argv) < 0)
    {
      perror("execv");
    }
    if(execvp("ls",argv) < 0)
    {
      perror("execvp");
    }
}

进程 - system

int system(const char *command);

进程回收

子进程结束时候由父进程回收

孤儿进程由init进程回收

若没有及时回收会出现僵尸进程


进程回收 - wait

pid_t wait(int *status);

成功时候返回进程好;失败时候返回EOF


若子进程没有结束,父进程一直阻塞


若有多个子进程,则哪个先结束先回收哪个子进程


status 置顶保存子进程返回值和结束方式的地址


status 为NULL标志直接释放子进程的PCB

nclude <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
    int status;
    pid_t pid;
    if((pid = fork()) < 0)
    {
        perror("fork");
        return -1;
    }
    if(pid == 0)
    {
        sleep(1); 
        exit(2);
    }
    else
    {
        wait(&status);
        printf("%x\n", status);
    }
}

子进程通过exit/_exit/return返回某个值(0-255);


父进程调用wait(&status)回收


WIFEXITED(status) 判断子进程是否正常结束

WEXITSTATUS(status) 获取子进程的返回值

WIFSIGNALED(status) 判断子进程是否被信号结束

WTERMSIG(status) 获取结束子进程的信号


进程回收 - waitpid

pid_t waitpid(pid_t pid, int *status, int option);

成功时返回回收的子进程的pid或0;失败时返回EOF


pid可用于指定回收哪个子进程或者任意子进程


status指定用于保存子进程返回值和结束方式的地址


option指定回收方式 0或者 WNOHANG

waitpid(pid, &status, 0);
waitpid(pid, &status, WNOHANG);
waitpid(-1, &status, 0);
waitpid(-1, &status, WNOHANG);

守护进程

守护进程(Daemon)是linux三种进程类型之一


通常在系统启动时运行,系统关闭时结束


Linux系统中大量使用,很多服务程序以守护进程形式运行


特点

 ● 始终在后台运行

 ● 独立于任何终端

 ● 周期性的执行某种任务或者等待处理特定事件


守护进程 - 会话、控制终端

Linux以会话(session)、进程组的方式管理进程

每个进程属于一个进程组(子进程和父进程在同一个进程组)

会话是一个或者多个进程组的集合。通常用户打开一个终端时,系统会创建一个会话。所有通过该终端运行的进程都属于这个会话

终端关闭时候,多有相关的进程都会被结束


守护进程 - 创建

1.创建子进程,父进程退出

if(fork>0)
{
    exit(0);
}

子进程变成孤儿进程,被init进程收养

子进程在后台运行


2.子进程创建新会话

if(setsid() < 0)
{
    exit(-1);
}

子进程成为新的会话组长

子进程脱离原先的终端


3.更改当前工作目录

chdir("/");
chdir("/tmp");

守护进程一直在后台运行,其工作目录不能被卸载

重新设定当前工作目录cwd


4.重设文件权限掩码

if(umask(0) < 0)
{
    exit(-1);
}

文件权限掩码设置为0

只影响当前进程


5.关闭打开的文件描述符

for(int i = 0; i < getdtablesize(), i++)
{
    close(i);
}

关闭所有从父进程继承的打开文件

已经脱离终端, stdin/ stdout/ stderr无法在使用

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/stat.h>
int main()
{
    pid_t pid;
    FILE *fp;
    time_t t;
    if((pid = fork()) < 0)
    {
        perror("fork");
        exit(-1);
    }
    if(pid > 0)
    {
        exit(0);
    }
    setsid();
    umask(0);
    chdir("/tmp");
    for(int i = 0; i < getdtablesize(); i++)
    {
        close(i);
    }
    if((fp = fopen("time.log","a+")) == NULL)
    {
        perror("fopen");
        exit(-1);
    }
    while(1)
    {
        time(&t);
        fprintf(fp, "%s", ctime(&t));
        fflush(fp); 
        sleep(1);
    }
}


目录
相关文章
|
13天前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第16天】进程、线程和协程是计算机程序执行的三种基本形式。进程是操作系统资源分配和调度的基本单位,具有独立的内存空间,稳定性高但资源消耗大。线程是进程内的执行单元,共享内存,轻量级且并发性好,但同步复杂。协程是用户态的轻量级调度单位,适用于高并发和IO密集型任务,资源消耗最小,但不支持多核并行。
34 1
|
2天前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
16 7
|
2天前
|
消息中间件 存储 安全
|
1天前
|
调度 Python
深入浅出操作系统:进程与线程的奥秘
【10月更文挑战第28天】在数字世界的幕后,操作系统悄无声息地扮演着关键角色。本文将拨开迷雾,深入探讨操作系统中的两个基本概念——进程和线程。我们将通过生动的比喻和直观的解释,揭示它们之间的差异与联系,并展示如何在实际应用中灵活运用这些知识。准备好了吗?让我们开始这段揭秘之旅!
|
25天前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
38 1
C++ 多线程之初识多线程
|
8天前
|
存储 并行计算 安全
C++多线程应用
【10月更文挑战第29天】C++ 中的多线程应用广泛,常见场景包括并行计算、网络编程中的并发服务器和图形用户界面(GUI)应用。通过多线程可以显著提升计算速度和响应能力。示例代码展示了如何使用 `pthread` 库创建和管理线程。注意事项包括数据同步与互斥、线程间通信和线程安全的类设计,以确保程序的正确性和稳定性。
|
11天前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
14天前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第15天】进程、线程和协程是操作系统中三种不同的执行单元。进程是资源分配和调度的基本单位,每个进程有独立的内存空间;线程是进程内的执行路径,共享进程资源,切换成本较低;协程则更轻量,由用户态调度,适合处理高并发和IO密集型任务。进程提供高隔离性和安全性,线程支持高并发,协程则在资源消耗和调度灵活性方面表现优异。
41 2
|
20天前
|
算法 安全 调度
深入理解操作系统:进程与线程的管理
【10月更文挑战第9天】在数字世界的心脏跳动着的,不是别的,正是操作系统。它如同一位无形的指挥家,协调着硬件与软件的和谐合作。本文将揭开操作系统中进程与线程管理的神秘面纱,通过浅显易懂的语言和生动的比喻,带你走进这一复杂而又精妙的世界。我们将从进程的诞生讲起,探索线程的微妙关系,直至深入内核,理解调度算法的智慧。让我们一起跟随代码的脚步,解锁操作系统的更多秘密。
28 1
|
25天前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
42 6

相关实验场景

更多