Linux_OS_code_to_sum_up(Linux系统编程总结)
来源:互联网 发布:poi导入excel数据库 编辑:程序博客网 时间:2024/06/06 14:15
一、系统组成
(1)系统:
1:软件(操作系统:内核,系统软件;应用程序)
2:硬件:CPU,内存,硬盘,键盘,鼠标,显卡 操作系统:内核或者内核和系统工具软件的组合
(2)启动和登录流程:上电,主板BIOS,boot,kernel,init,login,shell
配置文件:/ect/profile 系统启动时被执行~/.bashrc 用户登录时会调用
(3)文件:信息的集合,数据的集合,计算机处理的对象 IT行业处理信息:转换传输,存储
(4)错误处理:errno,strerror, perror
int main() { int fd = open("a.txt", O_RDWR); if(fd < 0){ printf("errno is %d, error string = %s\n", errno, strerror(errno)); perror("open"); } }
二、文件IO
(1)open/creat O_RDONLY、O_WRONLY、O_RDWR、O_CREAT(创建,如已存在,截断,需要增加文件权限)、O_TRUNC、O_APPEND、O_EXCL(与O_CREAT一起用,如存在则失败)
(2)close
(3)read/write
(4)文件指针,lseek
(5)文件读写效率,缓冲区(buf)设置1024~4096比较合适
(6)文件共享:两个进程同时打开同一个文件进行操作,会相互覆盖,有各自的文件指针
(7)dup:复制文件描述符,让文件描述符指向同一个文件结构
(8)原子操作:例:用APPEND写Log文件
(9)fcntl:这只文件描述符属性,文件状态属性,文件描述符复制,设置文件锁,设置文件通知等功能
例:添加O_APPEND属性
(10)文件映射 硬盘映射到进程的地址,效率高, 限制:文件长度必须大于等于映射长度,映射的offset必须是也得整数倍
页的尺寸获取方式:getconf -a | grep PAGE_SIZE
sysconf(_SC_PAGE_SIZE)
int main() { int fd = open("a.txt", O_RDWR); void *ptr = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); close(fd); *(char*)ptr = 'a'; munmap(ptr, 1024); //close (fd); }
(11)临时文件,mktemp
(12)缓存,O_SYNC(保证数据写入硬盘,IO效率低),sync/fsync/fsyncdata fwrite在用户空间和内核空间都有缓存,write只在内核空间有缓存
(13)标准输入0,标准输出1,标准错误2 STDIN_FLIENO,STDOUT_FILENO,STDERR_FILENO
(14)open返回值,可用最小文件描述符,文件描述符进程范围内唯一
(15)dup2(int oldfd, int newfd);
三、文件和目录:
Linux中的文件种类:普通文件、目录、符号链接,块设备,字符设备,管道,套接字
1、文件属性:stat
2、用户和组:实际账户和有限账户,文件权限(access测试文件某权限),umask 设置SUID,运行时使用拥有者的权限
3、文件长度,truncate,fseek,ftell
4、文件系统:inode(128-256Byte),数据块(1024-4096Byte) 文件、目录、引用计数器、stat(filename, struct stat *stat)/lstat
5、目录操作:opendir,closedir,readdir,rewinddir,telldir,seekdir
int rm(const char *path){ struct stat stat_buf; int ret = stat(path, &stat_buf); if(ret < 0){ perror("stat"); return -1; } if(!S_IS_DIR(stat_buf.st_mode)){ unlink(path); return 0; } char buf[1024]; DIR*dir = opendir(path); if(dir == NULL) return -1; struct dirent*entry = readdir(dir); while(entry){ sprintf(buf, "%s/%s", path, entry->d_name); if(entry->d_type == DT_REG || entry->d_type == DT_LNK) unlink(buf); if(entry->d_type == DT_DIR){ if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { entry = readdir(dir); continue; } rm(buf); } entry = readdir(dir); } close(dir); rmdir(path); return 0; } int main(){ long loc; DIR*dir = opendir("testdir"); struct dirent*entry; while(1){ loc = telldir(dir); entry = readdir(dir); if(entry == NULL) break; if(strcmp(entry->d_name, "a") == 0 break; } seekdir(dir, loc); while(1){ entry = readdir(dir); if(entry == NULL) break; printf("loc is %d, entry->d_name=%s\n", (int)telldir(dir), entry->d_name); } seekdir(dir, loc); }四、进程环境:
1、内核和进程的关系:当系统启动时,内核代码被夹在到内存,初始化之后,启动第一个用户进程,然后内核的代码就等着用户进程来调度了。
2、进程是程序的实例;
3、PCB:进程运行时,内核为每个进程分配一个PCB(进程控制块,结构体:task_struct),描述进程信息;
4、虚拟地址空间
5、CPU:内核将进程PCB放入一个队列,总是让CPU服务队列中的第一个进程,以时间片为单位运行,排队运行,时间到了丢到队尾;
6、进程属性和状态:
PID:进程编号,不会重复,pid_t getpid()
PPID:父进程ID,pid_t getppid()
账户ID/组ID:getuid/geteuid(真实账户/有效账户),getgid/getegid
进程组ID:getpgrp、setpgid/会话组ID:getsid、setsid/控制终端:
环境变量:setenv、getenv,unsetenv
进程状态: 进程时间:times
当前工作目录:getcwd
动态库编译: gcc -fPIC -share xxx.c -o libxxx.so
程序运行时: export LD_LIBRARY_PATH=. 或将动态库放到/usr/lib
静态库打包:ar rcs libtest.a a.o b.o 链接:gcc a.c -llib -static
五、进程控制:
1、fork
2、wait/waitpid
3、僵尸进程:已经退出,但是父进程还没有调用wait回收的紫禁城 孤儿进程:父进程退出,子进程没有退出
4、exec:鸠占鹊巢 使用fork和exec执行一个新程序
5、不定参数:
void myprint(const char *filename, int line, const char *fmt, ...)
va_list ap; va_start(ap, fmt); va_arg(ap, const char */int...); va_end(ap);
6、 进程间关系:在Linux中,父子关系,组关系,session关系,进程和终端进程关系
六、信号:内核和进程通信的一种方式
1、信号类型:实时信号,非实时信号
2、信号的处理:通过signal函数,注册信号处理函数、如果没有注册信号处理函数,那么按照默认方式处理。
3、不可靠信号:如果进程收到一个信号来不及处理,这时候有收到一个同样的信号,MAME这两个信号回合秉承一个信号,因为进程保存该信号的值只有一位
4、终端系统调用:如果一个进程调用了某系统调用导致该进程处于挂起状态,而此时该进程收到一个信号,那么该系统调用被唤醒,通常该系统调用返回-1,错误码EINTR。
5、可重入问题:
6、忽略信号:signal(SIGPIPE, SIG_IGN);
7、屏蔽信号:sigprocmask
8、SIGCHLD:
9、sigaction用来注册信号处理函数,sigqueue用来发送信号 sigaction可以传递参数,可以获得发送信号的进程信息,可以设置SA_RESTART
七、线程:
线程也有PCB,他的PCB和进程的PCB结构完全一样,保存的虚拟地址空间和创建它的进程的虚拟地址空间完全一致
1、pthread_create(pthread_t *thread, const pthread_attr_t *atr/NULL,void *(*start_routine)(void *), void *arg);
2、线程标识:使用pthread_t标识线程,他是非负整数,由系统分配,保证在晋城范围内唯一
使用pthread_equal判断线程是否相等,使用pthread_self获取目前代码运行的线程
3、线程终止:例程返回,pthread_exit,pthread_cancel(异常退出)
线程里调用exit退出整个进程,主线程调用pthread_exit进程不会退出,但是主线程已经推出了,如果主线程main函数return,那么其他线程也结束了
4、线程回收:pthread_join回收线程PCB,等待编程结束
5、线程的同步: 锁(临界量):避免两个线程同时访问一个全局变量
锁会有效率低和思索问题,解决方式:
读写锁: 循环锁:
基本锁:类型:pthrea_mutex_t 一般在全局定义:pthread_mutex_t g_mutex; 初始化:ptread_mutex_init(&g_mutex,NULL); 加锁:pthread_mutex_lock(&g_mutex); 解锁:ptread_mutex_unlock(&g_mutex);
锁的粒度越大,效率越低
死锁:忘了解锁,重复加锁
循环锁:同一个线程进行多次加锁,不会阻塞:pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_Mutex_init(&mutex, &attr);
读共享写排他锁:pthread_rwlock_t mutex; pthread_rwlock_init(&mutex, NULL); pthread_rwlock_rdlock(&mutex); pthread_rwlock_wrlock(&mutex); pthread_rwlock_unlock(&mutex);
6、C++使用构造函数和析构函数自动加锁解锁
7、条件变量: pthread_cond_t g_cond; pthread_cond_init(&g_cond); pthread_cond_wait(&g_cond,&g_mutex); pthread_cond_signal(&g_cond);//唤醒 pthread_cond_broadcast(&g_cond);//全部唤醒
8、信号量: sem_t sem; sem_init(&sem, 0, 0 // 信号量初始值); sem_wait(&sem);//成功后sem值-1 sem_pose(&sem);//sem+=1
9、重入:如果函数操作了全局变量,这个函数就不是可重入函数了
10、分离的线程运行结束之后,他的PCB同时被释放了
11、线程私有数据:线程私有数据可以在该县城调用函数中访问,其他线程调用的函数中,不可访问。
pthread_key_t key; pthread_key_create(&key, 用来清理私有数据的函数指针); pthread_set_specific(key, data); void *data = pthread_get_specific(key);
12、线程取消:pthread_cancel pthread_setcancelstate(...);
八、守护进程:Daemon
规则:设置umask为0; 调用fork,并让父进程退出;
调用setuid创建新会话; 重新设置当前目录;关闭不需要的文件描述符;
重定向标准输入,输出,错误到dev/null
出错处理:调式信息:<syslog.h> void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
int setlogmask(int maskpri);
单例:使用文件锁来实现单例
惯例:单例文件路径在/var/run目录下,内容为该进程ID;配置文件在/etc目录下;启动脚本通常放在/etc/init.d目录下
九、高级IO
1、非阻塞IO O_NONblOCK标记打开文件,read不到会返回-1,errno被标记为EAGAIN; 如果open没有带上O_NONBLOCK,可以通过fcntl设置
2、记录锁:
int main(){ int fd = open("a.txt", ORDWR);struct flock l; l.l_type = F_WRLOCK;l.l_whence = SEEK_SET; l.l_start = 0; l.l_len = 128; int ret = fcntl(fd, F_SETLKW, &l); l.l_type = F_UNLCK; fcntl(fd, F_SETLKW, &l); }
3、IO多路转接:
select:使用位域来表示描述符集合 让内核监听一个fd集合,当集合中有fd事件时,会返回有消息的fd子集
int main() { int fd_mice = open("/dev/input/mice", O_RDONLY); int fd_keyb = open("/dev/input/event1", O_RDONLY); int readlen; char buf[1024]; while(1){ fd_set set; FD_ZERO(&set); FD_SET(fd_mice, &set); FD_SET(fd_keyb, &set); int nfds = fd_keyb+1; struct timeval tv; tv.tv_sec = 2; tv.tv_userc = 0; int ret = select(nfds, &set, NULL, NULL, &tv); if(ret == -1){ if(errno == EINTR) continue; exit(1); } if(ret == 0) printf("not input\n"); if(FD_ISSET(fd_mice, &set) readlen = read(fd_mice, buf, sizeof(buf)); if(FD_ISSET(fd_keyb, &set) readlen = read(fd_keyb, buf, sizeof(buf)); } }
epoll:使用红黑树来保存文件集合
int main(){ int readlen; char buf[1024]; int fd_mice = open("/dev/input/mice", O_RDONLY); if(fd_mice < 0) return 1; int fd_keyb = open("/dev/input/event1",O_RDONLY); if(fd_keyb < 0) return 1; int epollfd = epoll_create(512); struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = fd_mice; int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_mice, &ev); if(ret < 0) perror("epoll_ctl mice"); ev.events = EPOLLIN; ev.data.fd = fd_keyb; ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_keyb, &ev); if(ret < 0) perror("epoll_ctl keyb"); sturct epoll_event out_events[2]; while(1){ int ret = epoll_wait(epollfd, out_events, 2, 2000); printf("epoll_wait return %d\n", ret); if(ret < 0){ if(errno == EINTR) continue; else exit(1); } if(ret == 0) printf("not input\n"); else{ int i; for(i = 0; i < ret; ++i){ struct epoll_event* p = &out_events[i]; if(p->data.fd == fd_mice) printf("mouse event"); else if(p->data.fd == fd_keyb) printf("keyboard event"); } } } }4、存储映射IO
- Linux_OS_code_to_sum_up(Linux系统编程总结)
- Linux系统编程总结
- Linux系统编程总结
- [Linux 系统编程] container_of 的一点总结
- linux系统编程系列讲座总结
- Linux下的系统编程总结
- Linux系统编程(一)
- Linux系统编程(二)
- Linux系统编程(三)
- linux 日志编程(总结)
- linux 日志编程(总结)
- Linux 编程总结(不断更新)
- linux 日志编程(总结)
- linux 日志编程(总结)
- linux系统编程之进程(二):fork函数相关总结
- linux系统编程之进程(二):fork函数相关总结
- linux系统编程之进程(二):fork函数相关总结
- Linux系统编程学习之《Git仓库使用总结》
- JS字符串转Byte[]
- dataguard归档不同步的问题解决思路及步骤
- Java中锁概念总结
- python 多线程另外一种写法
- java 小数点 四舍五入 方法
- Linux_OS_code_to_sum_up(Linux系统编程总结)
- 浅谈WebLogic和Tomcat
- 第二周项目二 程序的多文件组织
- JS 中的事件绑定、事件监听、事件委托是什么?
- jQuery滑动tab选项卡
- 加密解密算法java实现(3)—RSA --纯java.
- 【安全牛学习笔记】 端口扫描
- poj 2082 Terrible Sets(单调栈)
- 互动讨论总结和吐槽