我是靠谱客的博主 真实面包,最近开发中收集的这篇文章主要介绍《Unix环境高级编程》第二版 - 核心笔记(2/3),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

2017.05.28 ~ 2017.05.30
(立志成为终身学习者的第一个端午节3天假期用于复习+学习Unix高级编程)
全书总共21章,分为三个阶段,因有一定的基础,故只对核心知识点做笔记,主要是系统调用函数相关,便于后续对于unix函数的快速查找和使用,再届时根据实际需求针对性验证、使用到实际项目中。
第一阶段:Unix基础、Unix标准、文件I/O、文件和目录、标准I/O库、系统数据文件和信息
第二阶段:进程环境、进程控制、进程关系、信号、线程、线程控制、守护进程、高级I/O
第三阶段:进程间通信、网络IPC:套接字、高级进程间通信、终端I/O、伪终端、数据库函数库

ps: 选择第二版是因为该版pdf较清晰,以后有时间再快速浏览最新版第三版的内容差异。

【进程环境】


进程终止方式有8种。
5种正常终止:
    1.从main返回
    2.调用exit
    3.调用_exit或_Exit
    4.最后一个线程从其启动例程返回
    5.最后一个线程调用pthread_exit
3种异常终止:
    1.调用abort
    2.接到一个信号并终止
    3.最后一个线程对取消请求做出响应
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
功能:均可以正常终止一个程序。
参数:@status 终止状态

在main函数中,exit(0)等价于return(0)。
#include <stdlib.h>
int atexit(void (*function)(void));
功能:注册一个在正常进程终止时调用的函数
// 按照ISO C的规定,一个进程可以登记多达32个函数,由exit自动调用,这些函数成为 终止处理程序。POSIX.1扩展了其标准,若程序调用了exec函数族中任一函数,则将清除所有已注册的终止处理程序。

内核使进程执行的唯一方法是调用一个exec函数,进程自愿终止的唯一方法是显式或隐式地(exit)调用_exit或_Exit,进程也可以非自愿的由一个信号使其终止。

当执行一个程序时,调用exec的进程可将命令行参数传递给新程序。
    for (i = 0; argvp[i] != NULL; i++ )
    {
        printf ("argv[%d]: %sn", i, argv[i]);
    }

    $:' size ./a.out1 ./a.out2
    // size 命令可以查看可执行程序的代码段、数据段、bss段的总长度,以及16进制10进制总长度

内存分配:
#include <stdlib.h>
void *malloc(size_t size);                  // 未初始化
void *calloc(size_t nmemb, size_t size);    // 每一位都初始化为0
void *realloc(void *ptr, size_t size);      // 更改以前分配区长度,未初始化
功能:分配指定大小的动态内存
返回值:成功返回非空指针,指向分配的内存首地址;出错返回NULL

void free(void *ptr);
功能:释放动态内存(与分配成对出现,否则内存泄露)

环境参数表:
也是一个字符指针数组,每个指针包含一个以null结束的C字符串的地址。全局变量environ则包含了该指针数组的地址:
    extern char **environ;

大多数unix系统支持main函数的第三个参数,就是环境表的地址:
    int main (int argc, char *argv[], char *envp[]);

环境变量:name=value
#include <stdlib.h>
char *getenv(const char *name);
功能:获取环境变量值
返回值:指向name关联的value的指针,未找到返回NULL

#include <stdlib.h>
int setenv(const char *name, const char *value, int overwrite); // overwrite决定是否删除现有定义
int putenv(char *string);   // 若name存在,则删除现有的定义再设置
int unsetenv(const char *name);
功能:设置环境变量(unsetenv:删除name的定义)
返回值:成功返回0,出错返回非0

C语言中goto语句不能跨越函数,执行这类跳转功能的是函数 setjmp(3) 和 longjmp(3),这两个函数对于处理发生在深层次嵌套函数调用中的出错情况是非常有用的。

每个进程都有一组资源限制,可以用以下2个函数查询和更改:
#include <sys/time.h>
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim);
int setrlimit(int resource, const struct rlimit *rlim);
功能:获得或设置进程资源限制
返回值:成功返回0,出错返回非0
    struct rlimit {
       rlim_t rlim_cur;  /* Soft limit 软件限制 */
       rlim_t rlim_max;  /* Hard limit (ceiling for rlim_cur) 硬件限制 */
    };
常量" RLIM_INFINITY "指定了一个无限量的限制。

    $:' help ulimit
    $:' ulimit -S -a
    $:' ulimit -H -a
    // 打印系统当前的软资源S、硬资源H限制

【进程控制】


每个进程都有一个非负整数表示的唯一进程ID。
ID:0 ———— 系统调度进程,内核的一部分,不执行任何磁盘上的程序
ID:1 ———— init进程(1号进程),自举内核后启动一个unix系统,该进程绝不会终止
ID:2 ———— 页守护进程,负责支持虚拟存储系统的分页操作

获得进程ID号:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);     // 返回进程ID
pid_t getppid(void);    // 返回父进程ID
uid_t getuid(void);     // 返回进程实际用户ID
uid_t geteuid(void);    // 返回进程有效用户ID
gid_t getgid(void);     // 返回进程实际组ID
gid_t getegid(void);    // 返回进程有效组ID
功能:返回进程标识符(ID)

更改用户ID和组ID:
#include <sys/types.h>
#include <unistd.h>
int setuid(uid_t uid);
int setgid(gid_t gid);
功能:更改用户ID、组ID

创建子进程:
#include <unistd.h>
pid_t fork(void);
功能:创建一个子进程
返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1(执行1次,返回2次)

一个进程只会有1个父进程。
重定向父进程的标准输出时,子进程的标准输出也被重定向。

fork失败的两个主要原因:
1. 系统中已经有了太多的进程;
2. 实际用户ID的进程总数超过了系统限制;
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
功能:创建一个子进程(它保证子进程先运行,在它调用了exec或exit之后,父进程才被调度执行)

进程阻塞:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);    // status 有对应的宏检测进程返回的状态
pid_t waitpid(pid_t pid, int *status, int options);
功能:阻塞等待进程改变状态
返回值:成功返回进程ID,出错返回-1

#include <sys/types.h>
#include <sys/wait.h>
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
功能:阻塞等待进程改变状态,允许一个进程指定要等待的子进程

#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
功能:阻塞等待进程改变状态,返回由终止进程及其所有子进程使用的资源汇总

fork创建子进程后,子进程需要调用exec函数以执行另一个程序:
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
功能:执行一个新程序

>> exec系列函数详解链接: http://blog.csdn.net/sinat_36184075/article/details/54565358

解释器文件(interpreter file):
所有unix系统都支持解释器文件。其起始形式是:
    #! pathname [ optional-argument ]
最常见的解释器文件:
    #! /bin/sh
可以使我们能够编写shell脚本。

system函数:
#include <stdlib.h>
int system(const char *command);
功能:执行一个shell命令
返回值:成功返回command的退出状态码,失败返回-1

/* 将时间和日期放到某一文件中 */
    system ("date > filename");

用户标识:
#include <unistd.h>
char *getlogin(void);
功能:获得运行该程序的用户登录名。
返回值:成功返回指向登录名字符串的指针,出错返回NULL

进程时间:
#include <sys/times.h>
clock_t times(struct tms *buf);
功能:获得进程的时间
返回值:成功返回流逝的墙上时钟时间(滴答数),出错返回-1
    struct tms {
       clock_t tms_utime;  /* user time */
       clock_t tms_stime;  /* system time */
       clock_t tms_cutime; /* user time of children */
       clock_t tms_cstime; /* system time of children */
    };

【进程关系】


进程组:
每个进程出了有一个进程ID,还属于一个进程组,是多个进程的集合。
每个进程组有唯一的一个进程组ID。
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);
pid_t getpgid(pid_t pid);
pid_t getpgrp(void);                 /* POSIX.1 version */
pid_t getpgrp(pid_t pid);            /* BSD version */
int setpgrp(void);                   /* System V version */
int setpgrp(pid_t pid, pid_t pgid);  /* BSD version */
功能:设置/获取进程的组ID

会话:
会话是一个或多个进程组的集合。
#include <unistd.h>
pid_t setsid(void);
功能:创建一个会话,并设置返回一个进程组长ID

#include <unistd.h>
pid_t getsid(void);
功能:获取会话ID,即进程组长ID

控制终端:
一个会话可以有一个控制终端。
与控制终端连接的会话首进程被称为:控制进程。

简单理解: 代码逻辑 >> 多个函数->进程 >> 多个进程->进程组 >> 多个进程组->会话 >> 控制终端

通知内核进程组是前台进程组:
#include <unistd.h>
pid_t tcgetpgrp(int fd);
int tcsetpgrp(int fd, pid_t pgrp);
功能:获取/设置终端前台进程组

#define _XOPEN_SOURCE 500        /* See feature_test_macros(7) */
#include <termios.h>
pid_t tcgetsid(int fd);
功能:获得会话首进程ID(会话ID)

【信号】


信号是软件中断,信号提供了一种处理异步事件的方法,都有名字,都是以SIG大写开头。

>> 信号相关函数编程详解: http://blog.csdn.net/sinat_36184075/article/details/54565373

信号接口:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:信号处理操作

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:将信号发给进程或进程组

#include <signal.h>
int raise(int sig);
功能:允许进程向自身发送信号
raise (signo) <=等价于=> kill (getpid(), signo)

定时器函数:
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:为信号SIGALRM的发送设置一个时钟

#include <unistd.h>
int pause(void);
功能:使调用进程挂起直至捕捉到一个信号

信号集:
能够表示多个信号的数据类型。
#include <signal.h>
int sigemptyset(sigset_t *set);                     // 初始化set指向的信号集,清除其所有信号
int sigfillset(sigset_t *set);                      // 初始化set指向的信号集,使包括所有信号
int sigaddset(sigset_t *set, int signum);           // 将一个信号增加到现有集中
int sigdelset(sigset_t *set, int signum);           // 从信号集中删除一个信号
int sigismember(const sigset_t *set, int signum);   // 测试一个指定位
所有应用程序在使用信号集前,要对该信号集调用sigemptyset或sigfillset一次,进行初始化。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:检测或更改其信号屏蔽字,或在一个步骤中同时执行这两个操作。(该函数仅仅是为单线程定义的)

#include <signal.h>
int sigpending(sigset_t *set);
功能:检测信号集中的未决信号

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
功能:检测或更改信号处理动作,或同时执行这两种动作

sigsetjmp() sigsetlongjmp() 用于在信号处理程序中进行非局部转移。

#include <signal.h>
int sigsuspend(const sigset_t *mask);
功能:在一个原子操作中先恢复信号屏蔽字,然后使进程等待休眠

#include <stdlib.h>
void abort(void);
功能:使异常程序终止(此函数将SIGABRT信号发送给调用进程)

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
功能:休眠执行的时间秒数

【线程】


多线程的程序设计,并不会收到处理器数量的影响,多线程程序在单处理器上运行仍然能够改善相应时间和吞吐量。
线程包含了进程中标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。
进程的所有信息,包括程序代码段、全局内存、堆内存、栈内存、文件描述符等,都与该进程内的所有线程共享。

线程函数均需包含头文件: #include <pthread.h>
编译时候均需包含动态库: -pthread
int pthread_equal(pthread_t t1, pthread_t t2);
功能:对比两个线程ID

pthread_t pthread_self(void);
功能:获得自身的线程ID

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
功能:创建一个新的线程

void pthread_exit(void *retval);                    // 退出当前线程
int pthread_cancel(pthread_t thread);               // 给同一进程内的其他线程发送终止请求
int pthread_join(pthread_t thread, void **retval);  // 等待线程终止,回收线程资源
int pthread_detach(pthread_t thread);               // 分离一个线程,终止后资源自动回收
功能:终止一个线程(*retval是线程退出状态码,可强转为int类型并打印)

// 更好的可移植性和兼容性:pthread_exit ((void *)0);  线程退出状态码为0

线程可以安排它退出时需要调用的函数————线程清理处理程序:
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);
功能:压入或弹出一个线程清理处理程序/函数routine
// 当执行3个动作时调用routine处理程序:①调用pthread_exit时;②响应取消请求时;③用非零execute参数调用pthread_cheanup_pop时
// 注意:push和pop函数的使用匹配起来,否则程序编译可能通不过。

线程同步:
|互斥量|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 宏赋值方式
int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
int pthread_mutex_destroy (pthread_mutex_t *mutex);
功能:初始化互斥锁(任选其一)、销毁互斥锁

int pthread_mutex_lock (pthread_mutex_t *mutex );
int pthread_mutex_trylock (pthread_mutex_t *mutex);     // 线程不希望被阻塞,可以避免死锁
int pthread_mutex_unlock (pthread_mutex_t *mutex);
功能:对互斥量加锁、解锁

|读写锁|————比互斥锁允许更高的并行性
int pthread_rwlock_init (pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy (pthread_rwlock_t *rwlock);
功能:初始化读写锁、销毁读写锁

int pthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock (pthread_rwlock_t *rwlock);
功能:读模式下加锁、写模式下加锁、解锁

int pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock);
功能:尝试加锁

|条件变量|————条件变量与互斥锁一起使用,允许线程以无竞争的方式等待特定的条件发生
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   // 宏赋值方式
int pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr );
int pthread_cond_destroy (pthread_cond_t *cond);
功能:初始化条件变量(任选其一)、销毁条件变量

int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);  // 有等待的时间周期
功能:1. 解开mutex锁;2. 阻塞等待;3. 当条件成立的时候被唤醒,重新加锁。

int pthread_cond_signal (pthread_cond_t *cond );
功能:通知在cond条件上等待的线程,从中任选一个开始执行

int pthread_cond_broadcast (pthread_cond_t *cond);
功能:唤醒了所有在cond条件上等待的线程

【线程控制】


可以使用pthread_attr_t结构体修改线程默认属性,并把这些属性与创建的线程联系起来。

线程函数均需包含头文件: #include <pthread.h>
编译时候均需包含动态库: -pthread

线程属性:
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
功能:初始化一个线程属性对象、销毁一个线程属性对象

int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
功能:在线程属性对象中设置/获取线程分离状态属性
PTHREAD_CREATE_DETACHED  // 以分离状态启动线程
PTHREAD_CREATE_JOINABLE  // 以获取线程的终止状态

int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
功能:在线程属性对象中设置/获取线程栈属性

int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
功能:在线程属性对象中设置/获取线程栈大小属性

int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
功能:在线程属性对象中设置/获得溢出警戒栈大小属性

并发度控制着用户级线程可以映射的内核线程或进程的数目。
int pthread_setconcurrency(int new_level);
int pthread_getconcurrency(void);
功能:设置/获取并发级别

同步属性:
线程的同步对象也有属性。
|互斥量属性|
int pthread_mutexattr_init (pthread_mutexattr_t *attr);
int pthread_mutexattr_destory (pthread_mutexattr_t *attr);
功能:初始化、销毁一个互斥量属性对象

int pthread_mutexattr_getpshared (const pthread_mutexattr_t *restrict arrt, int *restrict pshared);
int pthread_mutexattr_setpshared (pthread_mutexattr_t *arrt, int pshared);
功能:获取、修改进程共享属性

int pthread_mutexattr_gettype (const pthread_mutexattr_t *restrict attr, int *restrict type);
int pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type);
功能:获取、修改互斥量类型属性

|读写锁属性|
pthread_rwlockattr_init ();
pthread_rwlockattr_destroy ();
pthread_rwlockattr_getpshared ();
pthread_rwlockattr_setpshared ();

|条件变量属性|
pthread_condattr_init ();
pthread_condattr_destroy ();
pthread_condattr_getpshared ();
pthread_condattr_setpshared ();
如果一个函数在同一时刻可以被多个线程安全的调用,就称该函数是线程安全的。
(不能保证线程安全的函数表 ———— 百度)

线程私有数据:
在分配线程私有数据之前,需要创建与改数据关联的键,这个键用于获取对线程私有数据的访问权。
pthread_key_create (); // 创建一个键
pthread_key_delete (); // 销毁一个键(取消键与线程私有数据之间的关系)

pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once (pthread_once_t *initflag, void (*initfn) (void)); // 保证initfn只被调用一次,解决线程调度竞争键值的问题

pthread_setspecific (); // 设置键与线程的私有数据地址的关联
pthread_getspecific (); // 获取与键关联的线程的私有数据地址

取消选项:
pthread_setcancelstate (); // 修改线程的可取消状态
pthread_testcancel (); // 在程序中自己添加取消点
pthread_setcanceltype (); // 修改线程的可取消类型

线程和信号:
每个线程多有自己的信号屏蔽字,但是信号的处理是进程中所有线程共享的。
pthread_sigmask (); // 线程中用来阻止信号发送
sigwait (); // 线程中等待一个或多个信号发送
pthread_kill (); // 把信号发送到线程

【守护进程】


守护进程也叫精灵进程( deamon),生存期较长的一种进程,常常在系统自举时启动。
自举有2个功能: 加电自检、磁盘引导
因为守护进程没有控制终端,所以说他们是后台运行的。
/* 初始化一个守护进程 */
/*
 * Copyright (c) 2010-~ zhouyongfei
 *
 * The source code is released for free distribution under the terms of the GNU General Public License
 *
 *
 * Author: xxx
 * Created Time: 2010年09月21日 星期二 20时27分20秒
 * File Name: testdaemon.c
 * Description:
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <fcntl.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

void daemonize(const char *cmd)
{
    int i,fd0,fd1,fd2;
    pid_t pid;
    struct rlimit rl;
    struct sigaction sa;

    //首先调用umask将文件模式创建屏蔽字设置为0
    umask(0);

    //得到每个进程能打开的最大数文件数
    if(getrlimit(RLIMIT_NOFILE , &rl) < 0){
        printf("%s:cannot get file limit",cmd);
        exit(0);
    }

    //创建一个子进程,然后父进程退出,这样保证了子进程不是一个进程组的组长进程
    if((pid = fork()) <0 ){
        printf("%s: cannot fork",cmd);
        exit(0);
    }else if(pid != 0){
        exit(0);
    }

    //利用这个子进程创建一个会话1,成为新会话的首进程,2,成为一个新进程组的组长,3,没有控制终端
    setsid();
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if(sigaction(SIGHUP,&sa,NULL) < 0){
        printf("%s,cannot ignore SIGHUP",cmd);
        exit(0);
    }

    if((pid = fork()) < 0){
        printf("%s:cannot fork()",cmd);
        exit(0);
    }else if(pid != 0){
        exit(0);
    }

    //改变当前的工作目录为根“/”目录
    if(chdir("/") < 0){
        printf("%s:cannot change directory tp /",cmd);
        exit(0);
    }

    //关闭当前进程打开的所有文件描述符
    if(rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for(i = 0;i < rl.rlim_max; i++)
        close(i);

    //将标准输入输出和标准操作输出都定向到/dev/null,让其不实现和标准输入输出等设备的交互
    fd0 = open("/dev/null" ,O_RDWR);
    fd1 = dup(0);
    fd2 = dup(0);

    //初始化一个系统日志,用于记录不能和终端交互的daemon进程的相关信息
    openlog(cmd,LOG_CONS,LOG_DAEMON);
    if(fd0 != 0 || fd1 != 1 || fd2 != 2){
        syslog(LOG_ERR,"unexpected file description %d %d %d",fd0,fd1,fd2);
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    daemonize("ls");
    sleep(10);//这里必须使用 sleep使其处于休眠状态,使用下面的死循环将不能看到实际的效果

    /*while(1){
        ;
    }*/
    return 0;
}

编译:$:' gcc testdaemon.c -o testdaemon
运行:$:' ./testdaemon
查看:
~/linuxc/process $:' ps aux | grep ./testdaemon
zhou 2622 0.0 0.0 1612 196 ? S 09:07 0:00 ./testdaemon
zhou 2624 0.0 0.0 3544 828 pts/0 S+ 09:07 0:00 grep –color=auto ./testdaemon
看上面查看的结果,2622进程的状态是S,终端名称号为?,这些都符合守护进程的特征,然后再使用ps命令查看,没有活动的进程的ID是2622,这说 明我们的守护进程在孤儿进程组中,他不是一个会话首进程,于是不会有机会分配到一个控制终端,所以,此守护进程被正确初始化了。

守护进程的出错信息通过系统日志函数查看:
openlog ();     // 可选调用
syslog ();      // 打开守护进程系统日志
closelog ();    // 关闭守护进程系统日志
setlogmask ();  // 设置进程的记录优先级屏蔽字
守护进程可用命令启动,但通常他们是由系统初始化脚本启动。
如:/etc/rc*   或   /etc/initd./*

【高级I/O】


(目前只记录函数,在实际使用到的时候再针对性的看单个例程)

记录锁:
fcntl (); // 当进程正在读或修改文件的某个部分时,它可以阻止其他进程修改同一文件区
putmsg (); // 将STREAMS消息写至流中
putpmsg (); // 将STREAMS消息写至流中,允许对消息指定优先级波段
isastream (); // 判断描述符是否引用一个流
getmsg (); // 从流首读STREAMS消息
getpmsg (); // 从流首读STREAMS消息

执行I/O多路转接,不会被阻塞:
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
void FD_CLR(int fd, fd_set *set); // 将一个指定位清除
int  FD_ISSET(int fd, fd_set *set); // 测试一指定位是否设置
void FD_SET(int fd, fd_set *set); // 设置一个fd_set变量的指定位
void FD_ZERO(fd_set *set); // 将一个指定的fd_set变量的所有位设置为0
int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask);

poll函数同seclet函数:(单独针对性的对实例查看该两个函数)
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout); // 构造pollfd结构数组
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <poll.h>
int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);

用于一次函数调用中读、写多个非连续缓冲区:
#include <sys/uio.h>
ssize_t readv (int fd, const struct iovec *iov, int iovcnt); // 散布读
ssize_t writev (int fd, const struct iovec *iov, int iovcnt); // 聚集写

当读写管道、网络设备或终端时,一次返回的数据可以少于要求的数据时,使用:
ssize_t readn (int fd, void *buf, size_t nbytes);
ssize_t writen (int fd, void *buf, size_t nbytes);

存储映射I/O:
将文件映射到内存区域中,对返回的地址的操作即是对该文件的操作。
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);



2017.05.29
第二阶段任务完成...

最后

以上就是真实面包为你收集整理的《Unix环境高级编程》第二版 - 核心笔记(2/3)的全部内容,希望文章能够帮你解决《Unix环境高级编程》第二版 - 核心笔记(2/3)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部