嵌入式学习-IO进程-Day03
IO进程
获取文件属性(stat)
头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数
int stat(const char *pathname, struct stat *statbuf);
功能:获取文件的属性
参数:pathname:文件
buf:获取文件属性存放的位置
成功返回0,失败返回-1,更新错误码
结构体包含
struct stat {
dev_t st_dev; /* ID of device containing file */
包含文件的设备ID
ino_t st_ino; /* inode number */文件的Inode号
mode_t st_mode; /* protection */ 文件类型和权限
nlink_t st_nlink; /* number of hard links */硬链接数
uid_t st_uid; /* user ID of owner */用户ID
gid_t st_gid; /* group ID of owner */组ID
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */大小
blksize_t st_blksize; /* blocksize for filesystem I/O *
文件系统I/O的块大小
blkcnt_t st_blocks; /* number of 512B blocks allocated */ 512B块的分配数量
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
从Linux 2.6开始,内核支持纳秒
以下时间戳字段的精度。
Linux 2.6之前版本的详细信息请参见“说明”。
struct timespec st_atim; /* time of last access访问 */
struct timespec st_mtim; /* time of last modification修改 */
struct timespec st_ctim; /* time of last status change *
打印文件的inode
下面是st_mode的解释
man 7 inode
在man手册的第七页,打开man 7 inode
The following mask values are defined for the file type:
对于该文件类型,定义了以下掩码值:
st_mode 包含的是文件类型和权限:
文件类型:
S_IFMT 0170000 bit mask for the file type bit field
文件类型位字段的位掩码
S_IFSOCK 0140000 socket-套接字
S_IFLNK 0120000 symbolic link-连接文件
S_IFREG 0100000 regular file-普通文件
S_IFBLK 0060000 block device块设备
S_IFDIR 0040000 directory目录
S_IFCHR 0020000 character 字符设备
S_IFIFO 0010000 FIFO管道
Thus, to test for a regular file (for example), one could write:
因此,要测试一个常规文件(例如),可以编写以下代码:
stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
/* Handle regular file */
}
获取st_mode的值
100664
&
170000
=
100000
S_ISREG(m) is it a regular file?
S_ISDIR(m) directory?
S_ISCHR(m) character device?
S_ISBLK(m) block device?
S_ISFIFO(m) FIFO (named pipe)?
S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.)
S_ISSOCK(m) socket? (Not in POSIX.1-1996.)
将使用规则封装:封装成宏函数
#define S_ISREG(m) (m&S_IFMT)==S_IFREG m就相当于获取到的st_mode的值
相当于if(S_ISREG(sb.st_mode))
权限:后9位控制权限
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and
execute permission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
使用方法:用谁与谁 st_mode & ???
// 创作者权限
if (st.st_mode & S_IRUSR)
putchar('r');
else
putchar('-');
1.getpwuid:通过用户id获取用户名
struct passwd *getpwuid(uid_t uid);
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
2.getgrgid:通过组id获取组名
struct group *getgrgid(gid_t gid);
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* group members */
};
3.char *ctime(const time_t *timep);
功能:将时间转换为字符串的格式表示
如:"Wed Jun 30 21:49:08 1993\n"
ctime(&st.st_mtime) 函数返回一个指向字符串的指针,这个字符串表示时间格式的日期和时间。标准的 ctime 函数返回的时间字符串格式如下:
Www Mmm dd hh:mm:ss yyyy\n\0
解释:
Www:表示星期几:MOn ,TUe
Mmm:表示月份:Jan,Feb
dd:表示日期
hh:mm:ss:时分秒
yyyy:年份。
代码实现ls-l功能
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
int main(int argc, char const *argv[])
{
struct stat sb;
if (stat("./a.txt", &sb) == -1)
{
perror("stat err");
return -1;
}
// type
if (S_ISREG(sb.st_mode))
{
putchar('-');
}
// mode_usr
if (sb.st_mode & S_IRUSR)
{
putchar('r');
}
else
{
putchar('-');
}
// mode_gru
if (sb.st_mode & S_IRGRP)
{
putchar('r');
}
else
{
putchar('-');
}
// mode_other
if (sb.st_mode & S_IROTH)
{
putchar('r');
}
else
{
putchar('-');
}
printf("%ld ", sb.st_nlink);
printf("%s ", getpwuid(sb.st_uid)->pw_name);
printf("%s ", getgrgid(sb.st_gid)->gr_name);
printf("%ld ",sb.st_size);
printf("%.12s",ctime(&sb.st_mtime));
printf("%s ","./a.out");
printf("\n");
return 0;
}
库
库的概念
就是把一些常用函数的目标文件打包在一起,提供相应函数的接口,便于程序员使用;本质上来说库是一种可执行代码的二进制形式
库的分类
静态库和动态库,本质区别是代码被载入时刻不同。
静态库:程序编译时连接到目标文件。
缺点:静态库中的代码复制到了程序中,因此体积较大。静态库升级后,程序需要重新编译链接
优点:程序运行时将不再需要该静态库;运行时无需加载库,运行速度更快
动态库:程序运行时被载入到代码当中
缺点:运行时需要加载动态库,运行速度慢,移植性差
优点:体积小,升级时候变得更加简单。
动态库 静态库
linux: .so .a
windows: .dll .lib
静态库的制作
将源文件编译生成目标文件
gcc -c xxx.c -o xxx.o
创建静态库,用ar 命令,将.o文件生成.a文件
ar crs libxxx.a xxx.o
lib:库的前缀 xxx.库名
链接库测试使用
gcc xxx.c -L指定库的路径 -l 指定的库名
动态库的制作
创建与地址无关的目标文件
gcc -fPIC -c xxx.c -o xxx.o
创建动态库
gcc -shared -o libxxx.so xxx.o
lib:库的前缀 xxx.库名
测试使用
gcc xxx.c -L指定库的路径 -l 指定的库名
执行
错误原因:
当加载动态库时,系统会默认从/lib或/usr/lib路径下查找库文件
解决方法:
1.把库拷贝到/usr/lib和/lib目录下
sudo cp libxxx.so /usr/lib
2.在LD_LIBRARY_PATH环境变量中加上库所在路径。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
注意:只在当前终端,终端关闭,环境变量消失。
3.添加/etc/ld.so.conf.d/*.conf文件
进程
进程和程序的区别
程序:
1. 编译好的可执行的二进制文件。
2. 存放在磁盘上,指令和数据的有序集合(文件)。
3. 静态的,没有任何的执行概念。
进程:
1. 独立的可调度的任务
2. 执行一个程序所分配的资源总称
3.进程就是程序的一次执行的过程
4.进程是动态的,包括创建,调度,执行和消亡
进程的特点
1.CPU调度进程时会给进程分配时间片(几毫秒~十几毫秒),当时间片用完后,cpu再进行其他进程的调度,实现进程的轮转,从而实现多任务的操作
2.系统会为每一个进程分配0-4g的虚拟空间,0-3g(用户空间)是每个进程所独有的,3g-4g(内核空间)是所有进程共有的。
进程三段
- 数据段:存放的是全局变量,常数,static修饰的变量等。
- 正文段:存放的是程序中的代码。
- 堆栈段:存放的是函数的返回地址,函数的参数以及程序中的局部变量
进程的类型
1.交互进程:该类进程是由shell控制和运行的。交互进程既可以在前台运行,也可以在后台运行。该类进程经常与用户进行交互,需要等待用户的输入,当接收到用户的输入后,该类进程会立刻响应,典型的交互式进程有:shell命令进程、文本编辑器等
2.批处理进程:该类进程不属于某个终端,它被提交到一个队列中以便顺序执行。比如数据备份。
3.守护进程:该类进程在后台运行。它一般在Linux启动时开始执行,系统关闭时才结束。
进程的运行状态
D uninterruptible sleep (usually IO)
R running or runnable (on run queue)
S interruptible sleep (waiting for an event to complete)
T stopped by job control signal
t stopped by debugger during the tracing
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z defunct ("zombie") process, terminated but not reaped by its parent
- 运行态(R):此时正在运行或者准备运行的进程。
- 睡眠态(等待态):可中断的睡眠态(S):处于等待状态中的进程,一旦被该进程等待的资源被释放,那么该进程就会进入运行状态。
- 不可中断的睡眠态(D):该状态的进程只能用wake_up()函数唤醒。
- 暂停态(T):进程被暂停或者终止
- 死亡态:进程结束 X
-
僵尸态(Z):当进程已经终止运行,但还占用系统资源,要避免僵尸态的产生
进程状态转换图(重点)
进程创建后,进程进入就绪态,当CPU调度到此进程时进入运行态,当时间片用完时,此进程会进入就绪态,如果此进程正在执行一些IO操作(阻塞操作)会进入阻塞态,完成IO操作(阻塞结束)后又可进入就绪态,等待CPU的调度,当进程运行结束即进入结束态。
进程的函数接口
创建进程fork
pid_t fork(void);
功能:创建子进程
返回值:
成功:在父进程中:返回子进程的进程号 >0
在子进程中:返回值为0
失败:-1并设置errno
示例代码:
fork函数创建的子进程的特点
标签:group,permission,Day03,st,mode,IO,进程,sb,嵌入式 From: https://blog.csdn.net/Xiaomo1536/article/details/142991396
- fork创建一个子进程,父进程返回子进程的pid,子进程中返回0。
- fork创建的子进程几乎拷贝了父进程所有的内容(三个段:堆栈、数据、代码),fork之前的代码被复制并不会被执行,fork之后的代码被复制并执行。
- fork创建进程一旦成功,进程之间的空间就相会独立。各自分配0-4G的虚拟内存空间
- fork创建进程之前打开的文件可以通过复制拿到同一个文件描述符 操作同一个文件(同一个文件指针)。
- 如果父进程退出,子进程没有退出,子进程会变成孤儿进程被init进程收养。变成后台进程。