【Linux】Linux操作系统——进程线程的创建以及零零碎碎的知识点

这系列文章是以专栏:趣谈Linux操作系统,Linux实战技能100讲以及网络编程实战为基础的,持续更新。

安装

dpkg安装

win下载exe,对于Linux来讲,也是类似的方法,可以下载rpm或者deb。这个就是Linux下面的安装包。为什么有两种呢?
因为Linux现在常用的有两大体系,一个是CentOS体系,一个是Ubuntu体系,前者使用rpm,后者使用deb。
以下只记录Ubuntu。
以下载jdk为例:

  1. 下载jdk.deb文件。
    这一步在ubantu系统的浏览器中进行,访问openJDK的官网,选择合适的.deb文件进行下载。通常会默认保存到~/Downloads文件夹。
  2. 打开终端
    在ubantu中,打开终端除了去应用里找还可以通过按 Ctrl + Alt + T 实现。
  3. 使用终端按照JDK
    通过打开的终端,还需要使用cd命令切换到包含已下载.deb文件的目录。通常是~/Downloads。
    然后使用sudo dpkg -i 文件名.deb命令在ubantu上安装JDK。这个步骤设计权限提升,所以需要使用sudo。
  4. 验证JDK的安装
    还是在同一个终端内,可以通过输入java -version来检查JDK是否正确安装。
查看安装

可以用dpkg -l查看安装的软件列表,-q就是query,a就是all,-l的意思就是list。

这个列表会很长,可以用grep搜索工具来找到特定的软件。

dpkg -l | grep jdk这个命令是将列出来的所有软件形成一个输出。| 是管道,用于连接两个程序,前面dpkg -l的输出就放进管道里面,然后作为grep的输入,grep将在里面进行搜索带关键词jdk的行,并且输出出来。

grep支持正则表达式,因此搜索的时候很灵活,再加上管道,这是一个很常用的模式。

如果你不知道关键词,可以使用dpkg -l | more和dkpg -l | less这两个命令,它们可以将很长的结果分页展示出来。这样你就可以一个个来找了。

more是分页后只能往后翻页,翻到最后一页自动结束返回命令行,less是往前往后都能翻页,需要输入q返回命令行,q就是quit。

删除

如果需要删除,可以用dpkg -r,-r就是remove。后面要接安装包,具体安装包是什么名字,用查看安装的方式看。

apt-get安装

相当于ubuntu的软件管家

可以根据关键词搜索,例如搜索jdk

yum search jdkapt-cache search jdk,可以搜索出很多很多可以安装的jdk版本。

如果数目太多,你可以通过管道grep、more、less来进行过滤。

选中一个之后,我们就可以进行安装了。你可以用yum install java-11-openjdk.x86\_64apt-get install openjdk-9-jdk来进行安装。

卸载

可以使用yum erase java-11-openjdk.x86\_64apt-get purge openjdk-9-jdk

Linux允许我们配置从哪里下载这些软件的,地点就在配置文件里面。

对于Ubuntu来讲,配置文件在/etc/apt/sources.list里。

其实无论是先下载再安装,还是通过软件管家进行安装,都是下载一些文件,然后将这些文件放在某个路径下,然后在相应的配置文件中配置一下。

例如,在Windows里面,最终会变成C:\Program Files下面的一个文件夹以及注册表里面的一些配置。

对应Linux里面会放的更散一点。

例如,主执行文件会放在/usr/bin或者/usr/sbin下面,其他的库文件会放在/var下面,配置文件会放在/etc下面。

解压缩下载

还有一种简单粗暴的方式就是将安装好的路径直接下载下来,然后解压缩成为一个整的路径。
首先需要将压缩包下载下来,win中一般是下载zip包,在Linux环境下一般下载的是.tar.gz的包,下载方式是在链接前面加上wget。

下载之后还需要解压缩,将压缩文件解压,win有winzip这种软件一键解压,Linux环境下可以使用tar程序,比如通过tar xvzf jdk-XXX_linux-x64_bin.tar.gz就可以解压缩了。

通过tar解压缩之后,需要配置环境变量,可以通过export命令来配置,相当于win中配置JAVA_HOME和PATH
export JAVA_HOME=/ROOT/JDK-XXX_LINUX-X64
export PATH=$JAVA_HOME/bin:$PATH
export命令仅在当前命令行的会话中管用,一旦退出重新登录进来,就不管用了。

如何让设置永久有效呢?在当前用户的默认工作目录中,如/root或者/home/cliu8下面,有一个.bashrc文件,这个文件是以点开头的,这个文件默认看不到,需要ls -la才能看到,a就是all。每次登录的时候,这个文件都会运行,因而把它放在这里。这样登录进来就会自动执行。当然也可以通过source .bashrc手动执行。

要编辑.bashrc文件,可以使用文本编辑器vim。如果默认没有安装,可以通过yum install vim及apt-get install vim进行安装。

通过vim .bashrc,将export的两行加入后,输入:wq,写入并且退出,这样就编辑好了。

运行

通过./filename

win的话点击exe就行
Linux不是根据后缀名来运行的。它的执行条件是这样的:只要文件有执行权限,都能到文件所在的目录下,通过./filename运行这个程序,前提是生成了可执行文件,.o或.c什么的都不对。

这是 Linux执行程序最常用的一种方式,通过shell在交互命令行里面运行

这种方式比较适合运行一些简单的命令,例如通过date获取当前时间。这种模式的缺点是,一旦当前的交互命令行退出,程序就停止运行了。

另外,假如没有生成可执行文件,仅仅只是编译了一下,那么gcc编译完是会默认输出一个文件是a.out的可执行文件,执行这个文件也可以。
就./a.out即可。

后台通过nohup运行

Linux运行程序的第二种方式,后台运行。
使用nohup命令。这个命令的意思是no hang up(不挂起),也就是说,当前交互命令行退出的时候,程序还要在。
最后加一个&,就表示后台运行,不会霸占命令行。

另外一个要处理的就是输出,原来什么都打印在交互命令行里,现在在后台运行了,输出到哪里呢?
输出到文件是最好的。
最终命令的一般形式为nohup command >out.file 2>&1 &

其中1表示文件描述符1,表示标准输出,2表示文件描述符2,表示标准错误输出,2>&1表示标准输出和错误输出合并了。合并到out.file里。

这个后台运行的进程如何关闭呢?假设启动的程序包含某个关键字,那么就可以使用下面的命令。
ps -ef |grep 关键字 |awk '{print $2}' |xargs kill -9
其中ps -ef可以单独执行,列出所有正在运行的程序,grep可以通过关键字找到咱们刚刚启动的程序。
awk工具可以很灵活地对文本进行处理,这里的awk '{print $2}'是指第二列的内容,是运行的程序ID。

我们可以通过xargs传递给kill -9,也就是发给这个运行的程序一个信号,让它关闭。

如果你已经知道运行的程序ID,可以直接使用kill关闭运行的程序。

以服务的方式运行

运行程序的第三种方式,以服务的方式运行。

例如常用的数据库MySQL,就可以使用这种方式运行。

例如在Ubuntu中,我们可以通过apt-get install mysql-server的方式安装MySQL,然后通过命令systemctl start mysql启动MySQL,通过systemctl enable mysql设置开机启动。

之所以成为服务并且能够开机启动,是因为在/lib/systemd/system目录下会创建一个XXX.service的配置文件,里面定义了如何启动、如何关闭。

学几个系统调用

进程管理

  • 启动的时候先创建一个所有用户进程的"祖宗进程"。
  • 父进程用fork调用子进程,创建的时候会将父进程的数据结构以及程序代码都拷贝一份给子进程。
  • 对于fork系统调用的返回值,如果当前进程是子进程,就返回0;如果当前进程是父进程,就返回子进程的进程号。
  • 然后通过if-else语句判断,如果是父进程,还接着做原来应该做的事情;如果是子进程,需要请求另一个系统调用execve来执行另一个程序。
  • 父进程要关心子进程的运行情况,有个系统调用waitpid,父进程可以调用它,将子进程的进程号作为参数传给它,这样父进程就知道子进程运行完了没有,成功与否。

内存管理

  • 每个进程都有自己独立的进程内存空间。
  • 项目执行计划书,相当于放进进程内存空间中的程序代码,称为代码段。
  • 对于进程的内存空间来讲,放进程运行中产生数据的这部分,我们称为数据段;其中局部变量的部分,在当前函数执行的时候起作用,当进入另一个函数时,这个变量就释放了;也有动态分配的,会较长时间保存,指明才销毁的,这部分称为
  • 物理空间有限,只有真的写入数据的时候,发现没有对应物理内存,才会触发一个中断,现分配物理内存。

介绍两个在堆里面分配内存的系统调用,brk和mmap。

  • 当分配的内存数量比较小的时候,使用brk,会和原来的堆的数据连在一起。
  • 当分配的内存数量比较大的时候,使用mmap,会重新划分一块区域。

文件管理

进程程序有一些是需要长时间保存的,就需要放在文件系统里。对于文件的操作,下面系统调用是重要的:

  • 对于已有的文件,可以使用open打开这个文件,close关闭。
  • 对于没有的文件,可以使用creat创建文件。
  • 打开文件以后,可以使用lseek跳到文件的某个位置。
  • 可以对文件的内容进行读写,读的系统调用是read,写的系统调用是write。

Linux有一个特点,就是一切皆文件:

  • 启动一个进程,需要一个程序文件,这是一个二进制文件。
  • 启动的时候,要加载一些配置文件,例如yml、properties等,这是文本文件;启动之后会打印一些日志,如果写到硬盘上,也是文本文件
  • 但是如果我想把日志打印到交互控制台上,在命令行上唰唰地打印出来,这其实也是一个文件,是标准输出stdout文件
  • 这个进程的输出可以作为另一个进程的输入,这种方式称为 管道,管道也是一个文件。
  • 进程可以通过网络和其他进程进行通信,建立的 Socket,也是一个文件。
  • 进程需要访问外部设备, 设备 也是一个文件。
  • 文件都被存储在文件夹里面,其实 文件夹 也是一个文件。
  • 进程运行起来,要想看到进程运行的情况,会在/proc下面有对应的 进程号,还是一系列文件。

每个文件,Linux都会分配一个文件描述符,这是一个整数。
有了这个文件描述符,我们就可以使用系统调用,查看或者干预进程运行的方方面面。所以说,文件操作是贯穿始终的,这是一切皆文件的优势。

项目异常处理与信号处理

项目遇到异常情况,就会需要发送一个信号。
什么样的异常信号发送给谁呢?

  • 在执行一个程序的时候,在键盘输入“CTRL+C”,这就是中断的信号,操作系统发送一个"SIGINT"(signal interrupt)信号给当前正在执行的程序,让他立刻停止。
  • 如果非法访问内存,操作系统发送一个"SIGSEGV"信号,这个信号的接受者是试图非法访问内存的进程
  • 当使用kill命令或函数时,操作系统会向指定的进程发送一个信号。信号的接收者是被指定的目标程序(通过进程ID或PID标识)。

进程间通信

进程之间的沟通方式有很多,首先是发个消息,不需要很长的数据,这种方式称为消息队列,通过msgget创建一个新的队列,msgsnd将消息发送到消息队列,而消息接收方可以使用msgrcv从队列中取消息。
需要交互的信息比较大的时候,可以使用共享内存的方式,就像两个项目组共享某一个会议室,这样数据也不需要拷来拷去。这时候,通过shmget创建一个共享内存块,通过shmat将共享内存映射到自己的内存空间,然后就可以读写了。
共享的这一块必然会存在资源竞争的问题,这就需要信号量机制的参与与管控。

网络通信

不同的Linux服务器需要交流必须遵循相同的网络协议,即TCP/IP网络协议栈。Linux内核中有对于网络协议栈的实现。

如何使用呢?用socket,可以通过socket系统调用建立一个socket,socket也是一个文件,也有一个文件描述符,也可以通过读写函数进行通信。
网络服务是通过套接字socket来提供服务的,可以想象成弄一根网线,一头插在客户端,一头插在服务端,然后进行通信,在通信之前,双方都要建立一个socket。

总结
在这里插入图片描述

实操记录:

创建进程

在Linux上写程序和编译程序,也想要一套开发套件,基于centOS 7的操作系统是执行命令yum -y groupinstall "Development Tools"
但是我只有ubantu,系统不同所以用的命令是:

//更新软件包列表,确保安装时使用最新的软件包信息
sudo apt update
//安装基本的开发工具集合,包括gcc,g++,make,以及其他开发所需要的工具和库
sudo apt install build-essential

在执行sudo apt update的时候遇到报错

ubuntu@ubuntu-virtual-machine:~$ sudo apt update
命中:1 http://security.ubuntu.com/ubuntu focal-security InRelease              
错误:2 http://cn.archive.ubuntu.com/ubuntu focal InRelease                     
  无法发起与 cn.archive.ubuntu.com:80 (2403:2c80:5::6) 的连接 - connect (101: 网络不可达) 无法连接上 cn.archive.ubuntu.com:80 (45.125.0.6)。 - connect (111: 拒绝连接)
错误:3 http://cn.archive.ubuntu.com/ubuntu focal-updates InRelease
  无法发起与 cn.archive.ubuntu.com:80 (2403:2c80:5::6) 的连接 - connect (101: 网络不可达)
**剩余错误省略**

原因在于ubantu无法连接到中国的镜像服务器,为了解决这个问题,可以更换ubantu软件源到一个可用的服务器。比如官方的ubantu服务器或者其他镜像服务器。
解决:
第一步,先备份
这一步主要是害怕一次更换不成功

sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

第二步,编辑源列表文件
这一步使用nano或者vim编辑都可以
nano是服务器自带的,vim需要下载,所以在这一步使用不了vim,因为我网络有问题啥都无法下载

sudo nano /etc/apt/sources.list

第三步,替换为清华大学镜像源
首先将sources.list文件内全部清空,Ctrl+K即可逐行删除
在将以下代码粘贴进去

# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse

nano语法中,按 Ctrl+O 保存文件,然后按 Enter 确认。按 Ctrl+X 退出编辑器。

之后就可以顺利执行sudo apt update了。

执行完毕后,把vim下载了,在把build-essential下载了。

写一个函数封装创建进程的逻辑,命名为process.c
vim环境,代码为:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

extern int create_process (char* program, char** arg_list);
int create_process (char* program, char** arg_list)
    {
   
   
        pid_t child_pid;
        child_pid = fork ();
        if (child_pid != 0)
            return child_pid;
        else {
   
   
            execvp (program, arg_list);
            abort ();
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值