【Linux】Linux开发常用api

在这里插入图片描述

博客主页:PannLZ
系列专栏:《Linux系统之路》
不要让自己再留有遗憾,加油吧!


文章目录

  • Linux入门常用api
    • 1.文件操作(系统io)
      • 1.1打开一个文件:open()
      • 1.2读取文件内容:read()
      • 1.3数据写入文件:write()
      • 1.4关闭文件:close()
      • 1.5改变文件偏移量:lseek()
      • 1.6获取文件信息stat
    • 2.线程进程相关
      • 2.1创建新进程:fork()
      • 2.2创建线程pthread_create()
      • 2.3连接(joining)已终止的线程
      • 2.4线程分离
      • 补充


Linux入门常用api

1.文件操作(系统io)

1.1打开一个文件:open()

open()调用既能打开一个业已存在的文件,也能创建并打开一个新文件。

#include 
#include 

int open(const char* pathname,int flags,.../*mode_t mode*/);
//return file descriptor on success,or -1 on error

stat是status的缩写

fcntl是file control的缩写

要打开的文件由参数 pathname 来标识。如果 pathname 是一符号链接,会对其进行解引用。
如果调用成功,open()将返回一文件描述符,用于在后续函数调用中指代该文件。若发生错误,
则返回−1,并将 errno 置为相应的错误标志。

参数 flags 为位掩码,用于指定文件的访问模式

标 志 用 途
O_RDONLY 以只读方式打开
O_WRONLY 以只写方式打开
O_RDWR 以读写方式打开
O_CLOEXEC 设置 close-on-exec 标志(自 Linux 2.6.23 版本开始)
O_CREAT 若文件不存在则创建之
O_DIRECT 无缓冲的输入/输出
O_DIRECTORY 如果 pathname 不是目录,则失败
O_EXCL 结合 O_CREAT 参数使用,专门用于创建文件
O_LARGEFILE 在 32 位系统中使用此标志打开大文件
O_NOATIME 调用 read()时,不修改文件最近访问时间(自 Linux 2.6.8版本开始)
O_NOCTTY 不要让 pathname(所指向的终端设备)成为控制终端
O_NOFOLLOW 对符号链接不予解引用
O_TRUNC 截断已有文件,使其长度为零
O_APPEND 总在文件尾部追加数据
O_ASYNC 当 I/O 操作可行时,产生信号(signal)通知进程
O_DSYNC 提供同步的 I/O 数据完整性(自 Linux 2.6.33 版本开始)
O_NONBLOCK 以非阻塞方式打开
O_SYNC 以同步方式写入文件

当调用 open()创建新文件时,位掩码参数 mode 指定了文件的访问权限。

访 问 模 式 描述
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以读写方式打开文件

1.2读取文件内容:read()

read()系统调用从文件描述符 fd 所指代的打开文件中读取数据。

#include 

ssize_t read(int fd, void *buf, size_t count);

count 参数指定最多能读取的字节数。(size_t 数据类型属于无符号整数类型。)

buffer 参数提供用来存放输入数据的内存缓冲区地址。缓冲区至少应有 count 个字节。\

1.3数据写入文件:write()

write()系统调用将数据写入一个已打开的文件中。

#include 

ssize_t write(int fd, const void *buf, size_t count);

buffer 参数为要写入文件中数据的内存地址

count参数为欲从 buffer 写入文件的数据字节数

fd 参数为一文件描述符,指代数据要写入的文件

1.4关闭文件:close()

close()系统调用关闭一个打开的文件描述符,并将其释放回调用进程,供该进程继续使用。 当一进程终止时,将自动关闭其已打开的所有文件描述符。

#include 

int close(int fd);

1.5改变文件偏移量:lseek()

文件偏移量是指执行下一个 read()或 write()操作的文件起始位置,会以相对于文 件头部起始点的文件当前位置来表示。文件第一个字节的偏移量为 0。

#include 
#include 

off_t lseek(int fd, off_t offset, int whence);

fd是文件描述符

offset是偏移量

whence是偏移量的基准位置。它的取值有三个

  • SEEK_SET: 开始位置
  • SEEK_CUR: 当前位置
  • SEEK_END: 末尾位置

为什么开始位置的后缀是**_SET**

实际上,在man手册中可以看出。这三个宏的描述是

  • SEEK_SET The offset is set to offset bytes.
  • SEEK_CUR The offset is set to its current location plus offset bytes.
  • SEEK_END The offset is set to the size of the file plus offset bytes.

1.6获取文件信息stat

利用系统调用 stat()、lstat()以及 fstat(),可获取与文件有关的信息,其中大部分提取自文件 i 节点。

#include 
#include 
#include 

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);

stat检查符号链接时,实际检查的是符号链接所引用的文件

lstat检查符号链接时,检查的是符号链接本身

fstat功能与stat相同,不过它的参数是文件的描述符

上述所有系统调用都会在缓冲区中返回一个由 statbuf 指向的 stat 结构,其格式如下:

struct stat {
    dev_t     st_dev;     /* 设备号(主设备号,次设备号)*/
    ino_t     st_ino;     /* inode的数量 */
    mode_t    st_mode;    /* 文件的类型和存取的权限 */
    nlink_t   st_nlink;   /* 硬链接的数量 */
    uid_t     st_uid;     /* 所用者的uid */
    gid_t     st_gid;     /* 所有者的组id */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size;    /* 总大小,字节数 */
    blksize_t st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime;   /* 最后访问时间(access)*/
    time_t    st_mtime;   /* 最后修改时间(modification)文件内容的改动时间 */
    time_t    st_ctime;   /* 最后改动时间(change)文件属性的改动时间 */
};

2.线程进程相关

2.1创建新进程:fork()

从父进程派生出子进程,子进程完全拷贝父进程的stack,data,heap segment。

两者并不共享地址空间,所以的变量是独立的,一方修改,另一方不会变化。

#include 

pid_t fork(void);

理解 fork()的诀窍是,要意识到,完成对其调用后将存在两个进程,且每个进程都会从 fork()
的返回处继续执行。

习惯用语

pid_t childPid		/*used in parent after successful fork() to record PID of child*/
swith(childPid = fork()){
    case -1:
    /*Handle error*/	/*fork() failed*/
    
    case 0:
    /*perform action specific to child*/	/*child of successful fork() come here*/
    
    default:
    /*Perform action specific to parent*/	/*Parent comes here after successful fork()*/
}

调用 fork()之后,系统将率先“垂青”于哪个进程(即调度其使用 CPU),是无法确定的

2.2创建线程pthread_create()

#include 

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,void *(*start)(void*),void *arg);
	Return 0 on success

新线程通过调用带有参数 arg 的函数 start(即 start(arg))而开始执行。

将参数 arg 声明为 void*类型,意味着可以将指向任意对象的指针传递给 start()函数。

如果需要向 start()传递多个参
数,可以将 arg 指向一个结构,该结构的各个字段则对应于待传递的参数。

参数 attr 是指向 pthread_attr_t 对象的指针,该对象指定了新线程的各种属性。

2.3连接(joining)已终止的线程

函数 pthread_join()等待由 thread 标识的线程终止。(如果线程已经终止,pthread_join()会立即返回)。这种操作被称为连接(joining)。

#include 

int pthread_join(pthread_t thread,void **retval);

若 retval 为一非空指针,将会保存线程终止时返回值的拷贝,该返回值亦即线程调用return 或 pthred_exit()时所指定的值。

如向 pthread_join()传入一个之前已然连接过的线程 ID,将会导致无法预知的行为。

若线程并未分离(detached),则必须使用ptherad_join()来进行连接。如果未能
连接,那么线程终止时将产生僵尸线程,与僵尸进程(zombie process)的概念相类似

2.4线程分离

默认情况下,线程是可连接的(joinable),也就是说,当线程退出时,其他线程可以通过调
用 pthread_join()获取其返回状态。有时,程序员并不关心线程的返回状态,只是希望系统在线程终止时能够自动清理并移除之。在这种情况下,可以调用 pthread_detach()并向 thread 参数传入指定线程的标识符,将该线程标记为处于分离(detached)状态。

#include 

int pthread_detatch(pthread_t thread);

使用 pthread_detach(),线程可以自行分离:pthread_detach(pthread_self());

一旦线程处于分离状态,就不能再使用 pthread_join()来获取其状态,也无法使其重返“可连接”状态。

补充

使用pthread_create创建的线程有两种状态:joinable和unjoinable。默认是joinable 状态

pthread_detach()和pthread_join()就是控制子线程回收资源的两种不同的方式。同一进程间的线程具有共享和独立的资源,其中共享的资源有堆、全局变量、静态变量、文件等公用资源。而独享的资源有栈和寄存器,这两种方式就是决定子线程结束时如何回收独享的资源。

如果是joinable状态,则该线程结束后(通过pthread_exit结束或者线程执行体任务执行完毕)不会释放线程所占用堆栈和线程描述符(总计8K多)等资源,除非在主线程调用了pthread_join函数之后才会释放。pthread_join函数一般应用在主线程需要等待子线程结束后才继续执行的场景。(pthread_join是一个阻塞函数,调用方会阻塞到pthread_join所指定的tid的线程结束后才被回收,但是在此之前,调用方是霸占系统资源的。 )

如果是unjoinable状态,则该线程结束后会自动释放占用资源。实现方式是在创建时指定属性,或者在线程执行体的最开始处添加一行:pthread_detach(pthread_self());不会阻塞,调用它后,线程运行结束后会自动释放资源,后者非常方便。

pthread_detach()即主线程与子线程分离,两者相互不干涉,子线程结束同时子线程的资源自动回收。

pthread_join()即是子线程合入主线程,主线程会一直阻塞,直到子线程执行结束,然后回收子线程资源,并继续执行。

可连接的线程 能够被其他线程回收或杀死,在其被杀死前,内存空间不会自动被释放。

可分离的线程 不能被其他线程回收或杀死,其内存空间在它终止时由系统自动释放。

在编译(**gcc**)包含pthread函数的程序时,要显式地链接线程库,即**-lpthread**。

你可能感兴趣的:(Linux系统之路,linux,运维,服务器,个人开发)