终端的启动流程

在Linux操作系统启动时,首先加载的进程就是init进程(ID为1),其余进程都是init进程产生的(fork,然后exec金蝉脱壳),因此系统中所有进程都可以看成是init进程的子孙进程。可以通过ps ajx命令查看任意进程的父进程,进行追溯可以发现,任意进程的开头都是init进程,init进程起源于0号进程,0号进程实际不存在。

文件与I/O中讲过,每个进程都可以通过一个特殊的设备文件/dev/tty访问它的控制终端。事实上每个终端设备都对应一个不同的设备文件(伪文件,不占用磁盘空间),/dev/tty提供了一个通用的接口,一个进程要访问它的控制终端既可以通过/dev/tty也可以通过该终端设备所对应的设备文件来访问。ttyname函数可以由文件描述符查出对应的文件名,该文件描述符必须指向一个终端设备而不能是任意文件。

终端的启动过程。简单来说,一个Linux系统启动,大致经历如下的步骤: init --> fork --> exec --> getty --> 用户输入帐号 --> login --> 输入密码 --> exec --> bash(文字终端)。init进程通过fork产生子进程,子进程调用exec函数族成为getty进程,即文字终端登陆界面,登陆成功后再调用exec函数族成为bash终端进程,在该终端中产生的任意子进程的控制终端都是该终端。对于设备终端,init进程fork子进程后,exec提供登陆界面,再exec成为桌面终端,再exec成为设备终端(伪终端)。

计算机的整个架构:计算机硬件→硬件驱动程序→系统调用→应用层,数据流的流向也是如此,对于输入则为硬件流向应用层(用户空间),对于输出则相反。硬件驱动程序负责读写实际的硬件设备(包括各种文件,磁盘),比如从键盘读入字符和把字符输出到显示器,线路规程(line disciline像一个过滤器(用来过滤键盘输入的内容),对于某些特殊字符并不是让它直接通过,而是做特殊处理,比如在键盘上按下Ctrl-z,对应的字符并不会被用户程序的read读到,而是被线路规程截获,解释成SIGTSTP信号发给前台进程,通常会使该进程停止。线路规程应该过滤哪些字符和做哪些特殊处理是可以配置的。

ttyname函数

由文件描述符查出对应的文件名,该文件描述符必须指向一个终端设备而不能是任意文件。

char *ttyname(int fd);     成功:终端名;失败:NULL,设置errno

//下面我们借助ttyname函数,通过实验看一下各种不同的终端所对应的设备文件名

#include <unistd.h>
#include <stdio.h>
int main(void)
{printf("fd 0: %s\n", ttyname(0));printf("fd 1: %s\n", ttyname(1));printf("fd 2: %s\n", ttyname(2));return 0;
}

[root@localhost 01_session_daemon_test]# ./ttyname

fd 0: /dev/pts/2

fd 1: /dev/pts/2

fd 2: /dev/pts/2    //可以看见标准输入、输出和错误输出对应的终端为pts/2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/385312.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

进程组(作业)

&#xff08;1&#xff09;概念和特性 进程组&#xff0c;也称之为作业。BSD于1980年前后向Unix中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在waitpid函数和kill函数的参数中都曾使用到。操作系统设计的进程组的概念&#xff0c;是为了简化对多…

437. 路径总和 III

给定一个二叉树&#xff0c;它的每个结点都存放着一个整数值。 找出路径和等于给定数值的路径总数。 路径不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节点&#xff09;。 二叉树不超过1000个节…

会话(session)

一组进程形成一个进程组&#xff0c;一组进程组形成一个会话&#xff0c;即一个会话中可以包括多个进程组。 &#xff08;1&#xff09;创建会话 创建一个会话需要注意以下6点注意事项&#xff1a;1.调用进程不能是进程组组长&#xff08;不能是父进程&#xff09;&#xff0…

508. 出现次数最多的子树元素和

给出二叉树的根&#xff0c;找出出现次数最多的子树元素和。一个结点的子树元素和定义为以该结点为根的二叉树上所有结点的元素之和&#xff08;包括结点本身&#xff09;。然后求出出现次数最多的子树元素和。如果有多个元素出现的次数相同&#xff0c;返回所有出现次数最多的…

1003 我要通过!(20)(20 分)

“答案正确”是自动判题系统给出的最令人欢喜的回复。本题属于PAT的“答案正确”大派送 —— 只要读入的字符串满足下列条件&#xff0c;系统就输出“答案正确”&#xff0c;否则输出“答案错误”。 得到“答案正确”的条件是&#xff1a; 1. 字符串中必须仅有P, A, T这三种字符…

网络终端

虚拟终端或串口终端的数目是有限的&#xff0c;虚拟终端&#xff08;字符控制终端&#xff09;一般就是/dev/tty1∼/dev/tty6六个&#xff0c;串口终端的数目也不超过串口的数目。然而网络终端或图形终端窗口的数目却是不受限制的&#xff0c;这是通过伪终端&#xff08;Pseudo…

线程的概念

线程&#xff08;LWP&#xff0c;light weight process&#xff09;是轻量级的进程&#xff0c;本质仍是进程&#xff08;在类unix环境下&#xff09;。进程有独立地址空间&#xff0c;拥有PCB&#xff1b;线程也有PCB&#xff0c;但没有独立的地址空间&#xff08;共享&#x…

1001. 害死人不偿命的(3n+1)猜想 (15)

卡拉兹(Callatz)猜想&#xff1a; 对任何一个自然数n&#xff0c;如果它是偶数&#xff0c;那么把它砍掉一半&#xff1b;如果它是奇数&#xff0c;那么把(3n1)砍掉一半。这样一直反复砍下去&#xff0c;最后一定在某一步得到n1。卡拉兹在1950年的世界数学家大会上公布了这个猜…

海量数据处理 (一)

现有海量日志数据保存在一个超级大的文件中&#xff0c;该文件无法直接读入内存&#xff0c;要求从中提取某天出访问百度次数最多的那个IP。 从这一天的日志数据中把访问百度的IP取出来&#xff0c;逐个写入到一个大文件中;注意到IP是32位的&#xff0c;最多有2^32个IP。同样可…

线程控制原语之pthread_self和pthread_create函数

注意&#xff1a;使用线程库函数用gcc编译时&#xff0c;要加参数&#xff1a;-lpthread&#xff08;libpthread.so&#xff09;&#xff0c;因为线程库函数属于第三方c库函数&#xff0c;不是标准库函数&#xff08;/lib、/usr/lib或者/usr/local/lib&#xff09;。 &#xf…

1005. 继续(3n+1)猜想 (25)

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里&#xff0c;情况稍微有些复杂。 当我们验证卡拉兹猜想的时候&#xff0c;为了避免重复计算&#xff0c;可以记录下递推过程中遇到的每一个数。例如对n3进行验证的时候&#xff0c;我们需要计算3、5、8、4、2、1&#…

C指针深度解析

&#xff08;1&#xff09;指针的概念 指针是一种数据类型&#xff0c;而内存地址是这种数据类型具体的值&#xff08;注意区分两者的概念&#xff09;。先说一下什么是内存地址&#xff1a;假设CPU的寻址方式是以字节寻址的&#xff0c;即每一个字节对应一个地址编号&#xf…

1007. 素数对猜想

让我们定义 dn 为&#xff1a;dn pn1 - pn&#xff0c;其中 pi 是第i个素数。显然有 d11 且对于n>1有 dn 是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。 现给定任意正整数N (< 105)&#xff0c;请计算不超过N的满足猜想的素数对的个数。 输入格式&…

线程共享全局变量(.data和.bbs)

线程默认共享数据段、代码段等地址空间&#xff0c;常用的是全局变量。而进程不共享全局变量&#xff0c;只能借助mmap。 //代码示例 #include <string.h> #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <string.h> …

1008 数组元素循环右移问题 (20)

一个数组A中存有N&#xff08;N&gt0&#xff09;个整数&#xff0c;在不允许使用另外数组的前提下&#xff0c;将每个整数循环向右移M&#xff08;M>0&#xff09;个位置&#xff0c;即将A中的数据由&#xff08;A~0~ A~1~……A~N-1~&#xff09;变换为&#xff08;A~N-…

C++设计模式之策略模式(Strategy)

Strategy策略模式作用&#xff1a;定义了算法家族&#xff0c;分别封装起来&#xff0c;让他们之间可以互相替换&#xff0c;此模式让算法的变化&#xff0c;不会影响到使用算法的客户。 UML图&#xff1a; 代码实现 #include <iostream> using namespace std;class St…

pthread_exit函数

void pthread_exit(void *retval); 参数&#xff1a;retval表示线程退出状态&#xff0c;通常传NULL。 作用&#xff1a;将单个线程退出。 注意几点&#xff1a; return的作用是返回到函数的调用点&#xff0c;如果是main函数中的return&#xff0c;则代表该进程结束&#x…

C++面试常见问题

背景色yellow 1 1. c如何防止一个类被其他类继承 >- 如果是仅仅为了达到这个目的可以直接把这个类的构造函数设置成私有的&#xff0c;这样就杜绝了其他类的继承。也相当于毁掉了这个类&#xff08;无法再创造出自己的对象&#xff09;。 那么怎么样既要保证这个类的完整性…

pthread_join函数

int pthread_join(pthread_t thread, void **retval); 作用&#xff1a;阻塞等待线程退出&#xff0c;获取线程退出状态。其作用对应进程中 waitpid() 函数。 成功&#xff1a;0&#xff1b;失败&#xff1a;错误号 strerror函数 参数&#xff1a;thread&#xff1a;线程I…

【C++ Priemr | 15】派生类向基类转换的可访问性

1. 只有当D公有继承B时&#xff0c;用户代码才能使用派生类向基类的转换&#xff1b;如果D私有继承B的方式是受保护的或者私有的&#xff0c;则用户代码不能使用该转换。 class A {}&#xff1b; class B : public A {}void function(const A&) {}int main() {B b;functio…