进程与线程 -- 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);
    }
}


目录
相关文章
|
10天前
|
Linux API C++
c++多线程——互斥锁
c++多线程——互斥锁
|
15天前
|
并行计算 调度 C++
|
2天前
|
Java 调度
【Java多线程】对进程与线程的理解
【Java多线程】对进程与线程的理解
9 1
|
2天前
|
安全 C++
C++多线程编程:并发与同步
C++多线程编程:并发与同步
7 0
|
3天前
|
算法 安全 调度
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
【C++入门到精通】 线程库 | thread类 C++11 [ C++入门 ]
13 1
|
10天前
|
调度
线程和进程的区别?
线程和进程的区别?
|
12天前
|
调度 Python 容器
【python】-详解进程与线程
【python】-详解进程与线程
|
16天前
|
运维 监控 Unix
第十五章 Python多进程与多线程
第十五章 Python多进程与多线程
|
17天前
|
安全 Java 调度
C++从入门到精通:3.3多线程编程
C++从入门到精通:3.3多线程编程
|
17天前
|
Java 数据库连接 数据处理
Python从入门到精通:3.1.2多线程与多进程编程
Python从入门到精通:3.1.2多线程与多进程编程

相关实验场景

更多