讨论光标共享情况
1.dup和dup2定义变量赋值都共享光标
2.使用两个描述符调用两次open函数打开同一个文件,不共享光标
#include <myhead.h>
int main(int argc, const char *argv[])
{
//1、描述符赋值给新的变量
char buff[1024] = "abcdefg";
int newfd;
int fd1 = open("./1.txt",O_RDWR);
if(fd1==-1)
{
perror("open");
return -1;
}
write(fd1,buff,sizeof(buff));
newfd = fd1;//新的变量当作描述符被赋值
lseek(newfd,3,SEEK_SET);//从文件开头移动3个字节
read(fd1,buff,sizeof(buff));
printf("%s\n",buff);
memset(buff,0,sizeof(buff));//清空buff
//2、两个描述符指向同一个文件
char str[100] = "";
int fd3,fd4;
fd3 = open("./2.txt",O_RDWR);
if(fd3==-1)
{
perror("open");
return -1;
}
fd4 = open("./2.txt",O_RDWR);
if(fd4==-1)
{
perror("open");
return -1;
}
lseek(fd3,3,SEEK_SET);//fd3从文件开头移动3个字节
read(fd4,str,sizeof(str));//读取fd4的光标
printf("%s",str);//输出
return 0;
}
stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
功能:获取文件的详细信息
参数1:文件路径和文件名
参数2:获取到的文件信息存储地址。
struct stat {
dev_t st_dev; /* 设备号 */
ino_t st_ino; /* Inode号 */
mode_t st_mode; /*文件类型和权限 */
nlink_t st_nlink; /* 硬链接数 */
uid_t st_uid; /* 所有者ID */
gid_t st_gid; /* 所有者组ID */
dev_t st_rdev; /* 特殊文件的设备号 */
off_t st_size; /* 最大容量按照字节存储 */
blksize_t st_blksize; /* 每一块大小,按照字节 */
blkcnt_t st_blocks; /* 块的数量 */
返回值:成功返回0,失败返回-1,并置位错误码。
#include <myhead.h>
int main(int argc, const char *argv[])
{
struct stat sb;
int res = stat("./09.c",&sb);//文件的信息存入sb结构体变量
if(res==-1)
{
perror("stat");
return -1;
}
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
return 0;
}
opendir和closedir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开文件目录,返回指向目录的指针。
参数:目录路径和名字
返回值:成功返回打开的目录指针,失败返回NULL,并置位错误码。
int closedir(DIR *dirp);
功能:关闭文件目录指针指向的文件。
参数:opendir返回的指针。
返回值:成功返回0,失败返回-1,并置位错误码。
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录里面的所有文件或者文件夹信息
参数:目录指针
返回值:成功返回目录指针指向的文件信息结构体,失败返回NULL,并置位错误码。
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
#include <myhead.h>
int main(int argc, const char *argv[])
{
DIR *dir = opendir("/home/ubuntu/24101/IO/IO-1/");//打开一个文件夹
if(dir==NULL)
{
perror("opendir");
return -1;
}
while(1)
{
struct dirent *hangzhou = readdir(dir);//读取文件夹的内容
if(hangzhou==NULL)
{
perror("readdir");
return -1;
}
printf("文件名:%s\n",hangzhou->d_name);
switch(hangzhou->d_type)//输出文件的类型
{
case DT_BLK:
printf("块设备文件\n");
break;
case DT_CHR:
printf("字符设备文件\n");
break;
case DT_DIR:
printf("目录文件\n");
break;
case DT_FIFO:
printf("管道文件\n");
break;
case DT_REG:
printf("普通文件\n");
break;
}
}
closedir(dir);//关闭文件夹
return 0;
}
进程(process)
程序的一次执行过程就是进程
1、进程概念:
时间片轮询 上下文切换。
1、进程1在3ms时间内运行结束,那么cpu会将进程1出队,继续询问进程2.
2、进程1需要8ms才能结束,那么cpu会在第5ms时将进程1,放入就绪队列尾部
3、进程1正好5ms运行结束cpu将进程1出队。
4、如果有外部优先级更高的事件打断进程1,进程1也会进入就绪队列等待。例如IO
2、进程内存管理
1、进程在创建时系统会从1G的物理内存中,通过mmu映射出4G的虚拟内存,其中0--3G的内存是所有进程的空间,进程间空间是独立的,但是3--4G的空间是内核空间,由所有进程共享。
2、注意在32位的操作系统中,1G物理内存映射出来4G虚拟内存,在64位的操作系统中,1G物理内存映射出来256T虚拟内存。
3、进程之间并不能直接进程数据交换,但是可以通过内核空间实现数据交换也就是进程间通信。
3、进程和程序区别
1、进程是动态的,随着程序的执行而创建,随着程序的结束而消亡。
2、程序是存储在内存的二进制文件,进程消亡程序并不会消失。
3、进程是动态,程序是静态。
4、进程种类
Linux系统中进程种类可以为三种:
1、交互进程,如vi编辑器,实现用户和主机之间的交流。
2、批处理进程,如gcc编译器的一步到位的编译,批处理进程将所有进程放入就绪队列,一次性全部运行结束。
3、守护进程,不受用户控制,不依赖于终端,随着系统的开启而开启,随着系统的关闭而消亡。
5、进程号
pid(process ID):当前进程的进程号。
ppid(parent process ID):父进程号。
每一个子进程都不会凭空产生,都由父进程创建而生(除了守护进程等伴随操作系统的特殊进程),
每一个子进程和其父进程都有自己的ID号,也就是进程号。
进入到该文件下:cd /proc/
可以查看操作系统中所有的进程号。
6、Linux下5个特殊进程
1、0号进程,又叫idel进程没有父进程,系统启动时创建的,维护系统运行,当系统内没有任何进程需要执行时运行0号进程,系统处于待机状态。
2、1号进程,又叫 init进程父进程就是0号进程,也被称为守护进程,当有子进程处于僵尸状态时,1号进程会为子进程收尸。
3、2号进程,又称为kthreadd进程,是调度进程,完成任务器各项任务的调度工作。
4、僵尸进程:父进程还在运行,但是子进程已经消亡,而父进程并没有回收子进程的资源,这时子进程就被称为僵尸进程。
5、孤儿进程:父进程已经消亡,但是子进程还在运行,此时子进程就被称为孤儿进程。
7、进程的shell指令(ps top kill pidof)
1、查看进程状态:ps -ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 1 1 1 ? -1 Ss 0 0:03 /sbin/init splash
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 I< 0 0:00 [rcu_gp]
2 4 0 0 ? -1 I< 0 0:00 [rcu_par_gp]
2 5 0 0 ? -1 I 0 0:00 [kworker/0:0-cgr]
2 6 0 0 ? -1 I< 0 0:00 [kworker/0:0H-kb]
2 8 0 0 ? -1 I< 0 0:00 [mm_percpu_wq]
2 9 0 0 ? -1 S 0 0:00 [ksoftirqd/0]
2 10 0 0 ? -1 I 0 0:02 [rcu_sched]
2 11 0 0 ? -1 S 0 0:00 [migration/0]
2 12 0 0 ? -1 S 0 0:00 [idle_inject/0]
2 14 0 0 ? -1 S 0 0:00 [cpuhp/0]
2 15 0 0 ? -1 S 0 0:00 [kdevtmpfs]
2 16 0 0 ? -1 I< 0 0:00 [netns]
2 17 0 0 ? -1 S 0 0:00 [rcu_tasks_kthre]
PPID:父进程进程号
PID:当前进程的进程号
PGID:当前进程组的进程号
TTY:如果是?表示不依赖于任何终端而运行。
STAT:进程的状态(S:可中断的休眠态,+:前台运行状态)
TIME:进程执行的时间
COMMAND:进程的名称。
2、查看进程的CPU占用率 ps -aux
ubuntu@ubuntu:proc$ ps -aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.3 159804 7232 ? Ss 10:23 0:03 /sbin/init splash root 2 0.0 0.0 0 0 ? S 10:23 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? I< 10:23 0:00 [rcu_gp] root 4 0.0 0.0 0 0 ? I< 10:23 0:00 [rcu_par_gp] root 5 0.0 0.0 0 0 ? I 10:23 0:00 [kworker/0:0-cgr] root 6 0.0 0.0 0 0 ? I< 10:23 0:00 [kworker/0:0H-kb] root 8 0.0 0.0 0 0 ? I< 10:23 0:00 [mm_percpu_wq] root 9 0.0 0.0 0 0 ? S 10:23 0:00 [ksoftirqd/0] root 10 0.0 0.0 0 0 ? I 10:23 0:02 [rcu_sched] root 11 0.0 0.0 0 0 ? S 10:23 0:00 [migration/0] root 12 0.0 0.0 0 0 ? S 10:23 0:00 [idle_inject/0] root 14 0.0 0.0 0 0 ? S 10:23 0:00 [cpuhp/0] root 15 0.0 0.0 0 0 ? S 10:23 0:00 [kdevtmpfs] root 16 0.0 0.0 0 0 ? I< 10:23 0:00 [netns] USER :当前用户 %CPU:CPU占用率 %MEM:内存占用率 START:创建时间
3、进程之间的树状关系 pstree
ubuntu@ubuntu:proc$ pstree
systemd─┬─ModemManager───2*[{ModemManager}]
├─NetworkManager─┬─2*[dhclient]
│ └─2*[{NetworkManager}]
├─VGAuthService
├─accounts-daemon───2*[{accounts-daemon}]
├─acpid
├─avahi-daemon───avahi-daemon
├─bluetoothd
4、查看进程间的关系 ps -ef
ubuntu@ubuntu:proc$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:23 ? 00:00:03 /sbin/init splash
root 2 0 0 10:23 ? 00:00:00 [kthreadd]
root 3 2 0 10:23 ? 00:00:00 [rcu_gp]
root 4 2 0 10:23 ? 00:00:00 [rcu_par_gp]
root 5 2 0 10:23 ? 00:00:00 [kworker/0:0-cgr]
root 6 2 0 10:23 ? 00:00:00 [kworker/0:0H-kb]
root 8 2 0 10:23 ? 00:00:00 [mm_percpu_wq]
root 9 2 0 10:23 ? 00:00:00 [ksoftirqd/0]
root 10 2 0 10:23 ? 00:00:02 [rcu_sched]
root 11 2 0 10:23 ? 00:00:00 [migration/0]
5、动态查看进程的状态 top
top - 14:13:35 up 3:50, 1 user, load average: 0.00, 0.01, 0.00
任务: 315 total, 1 running, 248 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.1 us, 2.1 sy, 0.0 ni, 95.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1987060 total, 130112 free, 1469492 used, 387456 buff/cache
KiB Swap: 969960 total, 874984 free, 94976 used. 331056 avail Mem
进程 USER PR NI VIRT RES SHR � %CPU %MEM TIME+ COMMAND
1649 ubuntu 20 0 600048 102164 28996 S 3.0 5.1 0:47.74 Xorg
1846 ubuntu 20 0 3041844 156168 41260 S 2.0 7.9 0:59.59 gnome-shell
2255 ubuntu 20 0 922236 75776 33960 S 1.7 3.8 0:38.26 x-terminal-emul
10 root 20 0 0 0 0 I 0.3 0.0 0:02.19 rcu_sched
647 avahi 20 0 47408 3244 2836 S 0.3 0.2 0:06.59 avahi-daemon
3455 root 20 0 0 0 0 I 0.3 0.0 0:08.05 kworker/0:2-eve
1 root 20 0 159804 7232 5244 S 0.0 0.4 0:03.49 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
5 root 20 0 0 0 0 I 0.0 0.0 0:00.02 kworker/0:0-cgr
6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kb
8 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 mm_percpu_wq
9 root 20 0 0 0 0 S 0.0 0.0 0:00.27 ksoftirqd/0
11 root rt 0 0 0 0 S 0.0 0.0 0:00.09 migration/0
12 root -51 0 0 0 0 S 0.0 0.0 0:00.00 idle_inject/0
8、向进程发送信号指令 kill
发送信号:kill -信号号 进程ID
8、进程状态和切换
1、进程创建后进入就绪队列
2、通过CPU的时间片轮询,处于运行态
3、如果被外部事件如IO,中断,会处于阻塞状态。
4、解除阻塞状态后,会重新进入到就绪队列。
5、直至运行结束处于消亡态。
9.进程的创建
fork函数
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
功能:创建子进程,子父进程空间独立,在父进程中返回值时子进程的ID,在子进
程中返回值是0,创建子进程失败返回-1.
参数:无
返回值:在父进程中返回值时子进程的ID,在子进程中返回值是0,创建子
进程失败返回-1。
创建子进程
#include <myhead.h>
int main(int argc, const char *argv[])
{
pid_t pid = fork();//创建子进程
if(pid==0)//进入到子进程执行流
{
//子进程执行流
printf("我是子进程\n");
}
else if(pid>0)//进入到父进程执行流
{
//进入到父进程执行流
sleep(1);
printf("我是父进程\n");
printf("父进程中子进程的ID:%d\n",pid);
}
else
{
perror("fork");
return -1;
}
printf("*************\n");//子父进程都会执行这行代码
while(1);
return 0;
}
写时拷贝技术
1、写时拷贝技术,当创建子进程后,子父进程空间在发生数据写操作时就独立。
2、子进程中对局部变量的操作不会影响到父进程,父进程中对局部变量的操作不会影响到子进程。
3、进程之间数据不共享。
1、讨论子父进程是否共享全局变量
fork之后子父进程独立运行,子进程拷贝了父进程的资源,所以子进程修改变量,不会影响到父进程内的变量。
#include <myhead.h>
int n = 100;
int main(int argc, const char *argv[])
{
pid_t pid = fork();//创建子进程
if(pid==0)//进入到子进程执行流
{
//子进程执行流
n = n+1;
printf("我是子进程 n= %d\n",n);
}
else if(pid>0)//进入到父进程执行流
{
//进入到父进程执行流
sleep(1);
printf("我是父进程n = %d\n",n);
printf("父进程中子进程的ID:%d\n",pid);
}
else
{
perror("fork");
return -1;
}
printf("*************\n");
while(1);
return 0;
}
局部变量不会共享
#include <myhead.h>
int main(int argc, const char *argv[])
{
int n = 100;
pid_t pid = fork();//创建子进程
if(pid==0)//进入到子进程执行流
{
//子进程执行流
n = n+1;
printf("我是子进程 n= %d\n",n);
}
else if(pid>0)//进入到父进程执行流
{
//进入到父进程执行流
sleep(1);
printf("我是父进程n = %d\n",n);
printf("父进程中子进程的ID:%d\n",pid);
}
else
{
perror("fork");
return -1;
}
printf("*************\n");
while(1);
return 0;
}
作业
#include <luochen.h>
int main(int argc, const char *argv[])
{
int fd1= open("./1.txt",O_RDONLY);
int fd2= open("./2.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
int fd3= open("./3.txt",O_RDONLY);
int fd4= open("./4.txt",O_CREAT|O_TRUNC|O_WRONLY,0664);
pid_t pid = fork();
if(pid==0)
{
if(-1==fd1)
{
perror("open");
return -1;
}
char buff[1024];
while(1)
{
int res = read(fd1,buff,sizeof(buff));
if(res == 0)
{
break;
}
write(fd2,buff,res);
}
}
if(pid>0)
{
if(-1==fd3)
{
perror("open");
return -1;
}
char buff[1024];
while(1)
{
int res = read(fd3,buff,sizeof(buff));
if(res == 0)
{
break;
}
write(fd4,buff,res);
}
}
return 0;
}
#include <luochen.h>
int main(int argc, const char *argv[])
{
int fd =open("./1.txt",O_RDONLY);
if(-1==fd)
{
perror("open");
return -1;
}
pid_t pid = fork();
int len = lseek(fd,0,SEEK_END);
int half = len/2;
if(pid>0)
{
//父进程
lseek(fd,0,SEEK_SET);
int fd1 = open("./5.txt",O_CREAT|O_TRUNC|O_WRONLY);
char *buff = malloc(sizeof(char)*half);
int res = read(fd,buff,half);
write(fd1,buff,res);
close(fd1);
}
if(pid == 0)
{
//子进程
lseek (fd,half,SEEK_SET);
int fd2 = open("./6.txt",O_CREAT|O_TRUNC|O_WRONLY);
char *buff = malloc(sizeof(char)*(len-half));
int res = read(fd2,buff,len-half);
close(fd2);
}
close(fd);
return 0;
}