Di Linux, melaksanakan ls akan menyebabkan panggilan sistem baca dan eksekusi; melaksanakan sebarang perintah shell akan memanggil fork dan exec, tetapi jika anda menggunakan strace untuk menyemak panggilan sistem yang disebabkan oleh ls, tiada fork arahan mesti disenaraikan Fail dalam direktori, jadi baca mesti dipanggil.
Persekitaran pengendalian tutorial ini: sistem linux7.3, komputer Dell G3.
Jawapannya adalah siri baca dan laksanakan
The mekanisme pelaksanaan perintah shell ialah fork exec, fork ialah klon, dan execve ialah transformasi. Perintah ls menyenaraikan fail dalam direktori, jadi baca juga akan dipanggil.
Akses shell kepada kernel Linux dicapai melalui perintah fork dan exec Perintah fork boleh mencipta benang yang sama.
Gunakan strace untuk menyemak panggilan sistem yang disebabkan oleh ls Memang benar tiada fork, tetapi kerana melaksanakan mana-mana arahan shell akan memanggil fork
eksekusi Transformasi adalah untuk mencipta proses baharu dan menggantikan proses asal dengan proses baharu.
Pertama sekali, mari kita bincangkan apakah panggilan sistem?
Pengguna boleh mengakses dan mengawal fail dan peranti dengan bantuan sebilangan kecil fungsi yang disediakan secara langsung oleh UNIX/linux Fungsi-fungsi ini adalah 系统调用
[1].
Menggunakan perintah strace ls
kita boleh melihat panggilan sistem yang digunakan oleh arahan ls [2], sebahagian daripada output adalah seperti berikut:
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = 3 getdents64(3, /* 68 entries */, 32768) = 2240 getdents64(3, /* 0 entries */, 32768) = 0 close(3) = 0
panggilan sistem terbuka membuka arus fail direktori dan mengembalikan deskriptor fail yang diperolehi. Anda boleh melihat bahawa fail dibuka dengan bendera O_RDONLY.
Selagi fail dibuka dengan bendera O_RDONLY atau O_RDWR, bait boleh dibaca daripada fail menggunakan panggilan sistem read()
[3].
Jadi ls
perlu menggunakan read
panggilan sistem. Di samping itu, sebarang arahan shell yang mencipta proses akan menggunakan panggilan sistem exec.
Mari kita kembali dan selesaikan keraguan yang mungkin ada pada konsep ini:
Setiap atur cara berjalan dipanggil proses [1]
Unix mencipta dan memuatkan imej proses baharu Pemisahan imej. Kelebihan ini ialah terdapat lebih banyak kelonggaran untuk menguruskan kedua-dua operasi. Selepas kami membuat proses, kami biasanya menggantikan proses anak dengan imej proses baharu. Jadi sebarang arahan shell akan mencipta proses dan menggunakan panggilan sistem exec.
Contohnya: apabila melaksanakan perintah ps pada baris arahan shell, proses shell sebenarnya memanggil fork untuk menyalin proses anak baharu, dan kemudian menggunakan panggilan sistem exec untuk menggantikan sepenuhnya proses anak yang baru dijana dengan proses ps.
Gunakan fungsi exec untuk menggantikan proses semasa dengan proses baharu, dan proses baharu mempunyai PID yang sama seperti proses asal. Di bawah nama exec ialah siri lengkap yang terdiri daripada berbilang fungsi yang berkaitan [4]
Selepas memanggil fork untuk mencipta proses baharu, proses induk dan proses anak adalah hampir sama [1, p398].
Fork ialah istilah UNIX Apabila proses (program berjalan) dicabang, ia pada asasnya disalin, dan kedua-dua proses selepas garpu terus berjalan dari titik pelaksanaan semasa, dan setiap Setiap proses mempunyai sendiri. salinan ingatan.
Proses asal ialah proses induk, dan proses baharu ialah proses anak. Boleh dibezakan dengan fork()
nilai pulangan.
Panggilan fork dalam proses induk mengembalikan pid (id proses) proses anak baharu, manakala panggilan fork dalam proses anak mengembalikan 0
Sebagai contoh :
#include<unistd.h> #include<stdio.h> #define LEN 10 int main() { pid_t id=getpid(); printf("Main pid: %d \n",id); int i; pid_t res=fork(); if(res==0) { for(i =0;i<LEN;i++) { pid_t id1=getpid(); printf("%d ",id1); printf("Child process:%d\n",i); } } else { printf("res %d\n",res); for(i=0;i<LEN;i++) { pid_t id2=getpid(); printf("%d ",id2); printf("parent process:%d\n",i); } } printf("THE END\n"); return 0; } /*output Main pid: 10965 res 10966 10965 parent process:0 10965 parent process:1 10965 parent process:2 10965 parent process:3 10965 parent process:4 10965 parent process:5 10965 parent process:6 10965 parent process:7 10965 parent process:8 10965 parent process:9 10966 Child process:0 10966 Child process:1 THE END 10966 Child process:2 10966 Child process:3 10966 Child process:4 10966 Child process:5 10966 Child process:6 10966 Child process:7 10966 Child process:8 10966 Child process:9 THE END */
Apakah yang perlu anda lakukan jika anda mahu program memulakan pelaksanaan program lain tetapi anda masih mahu meneruskannya? Iaitu untuk menggabungkan fork dan exec [6][1, p397]
Sebagai contoh (diubah suai daripada [6]):
#include<string.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include<unistd.h> char command[256]; void main() { int rtn; /*子进程的返回数值*/ while(1) { /* 从终端读取要执行的命令 */ printf( ">" ); fgets( command, 256, stdin ); command[strlen(command)-1] = 0; if ( fork() == 0 ) {/* 子进程执行此命令 */ execlp( command, NULL ); /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ perror( command ); exit( errno ); } else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */ pid_t sonid=wait ( &rtn ); printf(" child pid: %d\n",sonid); printf( " child process return %d\n", rtn ); } } } /*output:错误命令、需要参数命令、正确命令 >aa aa: No such file or directory child pid: 11230 child process return 512 >echo A NULL argv[0] was passed through an exec system call. child pid: 11231 child process return 134 >ps child pid: 11247 child process return 139 */
Fork dahulu, dan kemudian proses anak menggunakan exec Panggil arahan program. Sediakan output yang sepadan untuk arahan ralat, arahan yang memerlukan parameter dan arahan yang tidak memerlukan parameter.
Semua peranti boleh dianggap sebagai fail.
对内核而言,所有打开的文件都通过文件描述符引用[7]。文件描述符是非负整数,范围是[0,OPEN_MAX -1]。现在OPEN_MAX 一般为64
但是[7]又说对于FreeBSD 8.0,Linux 3.2.0 ,Mac OS X 10.6.8等, fd变化范围几乎无限,只受到存储器数量、int字长以及系统管理员所配置的软限制和硬限制的约束。。。why?
当open或者create一个新文件时,内核向进程返回一个文件描述符。
当读、写一个文件时,使用open或create返回的文件描述符标识该文件,将其作为参数传送给read / write
按照惯例,fd为0 / 1 / 2分别关联STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO。这些常量也定义在unistd.h
.
包括exec、fork、read、write在内,许多系统调用包含在unistd.h
头文件中
POSIX,Portable Operating System Interface。是UNIX系统的一个设计标准,很多类UNIX系统也在支持兼容这个标准,如Linux。unistd.h
是POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型[5]。在该头文件,用于访问设备驱动程序的底层函数(系统调用)有这五个:open/close/read/write/ioctl
[1]。
[7]中提到大多数文件I/O用到的5个函数为:open/read/write/lseek/close
调用read函数从打开文件中读数据。
#include<unistd.h> ssize_t read(int filedes, void *buf, size_t nbytes);
返回值:
成功,读出的字节数;
失败,-1;
遇到文件尾,0
有多种情况可使实际读到的字节数少于要求读的字节数:
例如,若在到达文件尾端之前还有30个字节,而要求读100个字节,则read返回30,下一次再调用read时,它将回0。
当从终端设备读时,通常一次最多读一行
当从网络读时,网络中的缓冲机构可能造成返回值小于所要求读的字节数。
当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么read将只返回实际可用的字节数。
当从某些面向记录的设备(例如磁盘)读时,一次最多返回一个记录。
当某一信号造成中断,而已经读了部分数据量时。读操作从文件的当前偏移量出开始,在成功返回之前,该偏移量将增加实际独到的字节数
read的经典原型定义则是:
int read(int fd, char*buf, unsigned nbytes);
相关推荐:《Linux视频教程》
Atas ialah kandungan terperinci Apakah panggilan sistem yang akan disebabkan oleh melaksanakan ls dalam Linux?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!