记录技术 分享生活

一个不知道该写什么的人

记录技术 分享生活

最近在迁移服务器的时候,涉及到操作系统的替换和升级,导致一些C++依赖的项目无法在新系统中运行。由于某些原因,无法在新环境编译旧的服务,只能安装旧的依赖。
在Ubuntu20.04中,没有那么旧的依赖可以直接安装,只能自己编译。因为Gcc5.x中添加了对某些C++11的支持,更改了ABI,所以必须使用4.X编译依赖库,需要使用Ubuntu14.04。
下面是编译使用的Dockerfile

libprotobuf.so.17.0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM ubuntu:14.04

RUN apt-get update \
&& apt-get install -y git \
g++ \
make \
wget \
autoconf \
libtool \
automake

# 文档地址:https://github.com/protocolbuffers/protobuf/tree/v3.6.1.3/src
# 如果因为网络原因导致压缩包下载缓慢,可以下载到本地再使用COPY命令,复制Docker中
# COPY protobuf-3.6.1.3.tar.gz /home
RUN cd /home && wget -O protobuf-3.6.1.3.tar.gz https://github.com/protocolbuffers/protobuf/archive/refs/tags/v3.6.1.3.tar.gz \
&& tar xfz protobuf-3.6.1.3.tar.gz \
&& rm protobuf-3.6.1.3.tar.gz \
&& cd protobuf-3.6.1.3 \
&& ./autogen.sh \
&& ./configure --prefix=/usr/ \
&& make \
&& make install \
&& cd /home \
&& rm -rf protobuf-3.6.1.3

CMD ["bash"]

boost 1.53.0

例如boost_thread-mt.so.1.53.0直接可以软连接到boost_thread.so.1.53.0上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
FROM ubuntu:14.04

RUN apt-get update \
&& apt-get install -y git \
g++ \
make \
wget

# 如果因为网络原因导致压缩包下载缓慢,可以下载到本地再使用COPY命令,复制Docker中
# COPY boost_1_53_0.tar.gz /home
RUN cd /home && wegt http://downloads.sourceforge.net/project/boost/boost/1.53.0/boost_1_53_0.tar.gz \
&& tar xfz boost_1_53_0.tar.gz \
&& rm boost_1_53_0.tar.gz \
&& cd boost_1_53_0 \
&& ./bootstrap.sh --prefix=/usr/local --with-libraries=program_options,regex,date_time,filesystem,system,thread \
&& ./b2 install \
&& cd /home \
&& rm -rf boost_1_53_0

CMD ["bash"]

复制文件

  • 使用docker run启动容器以后,再使用docker cp命令复制容器中的文件
  • 使用docker save命令压缩image,然后解压缩

Reference

NSQ安装说明

使用docker-compose运行

如果使用docker-compose的方式运行nsq,首先要保证Consumer要与nsq服务在一个docker网络环境中。
如果不能保证在一个网络环境中,则需要从源代码安装。
如果要存储nsq的消息,需要在启动nsqd的时候加上--data-path=/data命令,并在docker配置文件中将/data使用-v--volume命令挂载到本地。
使用docker-compose up -d后台运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: '3'

services:
nsqlookupd:
image: nsqio/nsq
networks:
- nsq-network
hostname: nsqlookupd
ports:
- "4161:4161"
- "4160:4160"
command: /nsqlookupd
nsqd:
image: nsqio/nsq
depends_on:
- nsqlookupd
hostname: nsqd
volumes:
- ./data:/data
networks:
- nsq-network
ports:
- "4151:4151"
- "4150:4150"
command: /nsqd --broadcast-address=nsqd --lookupd-tcp-address=nsqlookupd:4160 --data-path=/data
nsqadmin:
image: nsqio/nsq
depends_on:
- nsqlookupd
hostname: nsqadmin
ports:
- "4171:4171"
networks:
- nsq-network
command: /nsqadmin --lookupd-http-address=nsqlookupd:4161

networks:
nsq-network:
driver: bridge

运行的独立的docker

  1. 从dokcer hub拉取最新的镜像docker pull nsqio/nsq
  2. 运行nsqlookupd
    1
    docker run --name lookupd -p 4160:4160 -p 4161:4161 nsqio/nsq /nsqlookupd
  3. 运行nsqd,需要手动挂载volume
    1
    2
    3
    4
    5
    docker run -v ./data:/data --name nsqd -p 4150:4150 -p 4151:4151 \
    nsqio/nsq /nsqd \
    --broadcast-address=127.0.0.1 \
    --lookupd-tcp-address=127.0.0.1:4160 \
    --data-path=/data
  4. 运行nsqadmin
    1
    2
    3
    docker run --name nsqadmin -p 4171:4171 \
    nsqio/nsq /nsqadmin \
    --lookupd-http-address=127.0.0.1:4161

从源代码安装

1
2
3
4
git clone https://github.com/nsqio/nsq $GOPATH/src/github.com/nsqio/nsq
cd $GOPATH/src/github.com/nsqio/nsq
dep ensure
go install

启动nsqlookupd

1
nsqlookupd

启动nsq

1
nsqd –lookupd-tcp-address=127.0.0.1:4160 --broadcast-address=127.0.0.1 --data-path=/data 

启动nsqadmin

1
nsqadmin --lookupd-http-address=127.0.0.1:4161

smtp之golang标准库

函数SendMail就是标准库里面最简单的发送邮件的方法。

1
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error

对不熟悉smtp协议的小伙伴来说,最难的地方就是构造msg了。
在指定smtpRFC531中,定义了smtp客户端和服务器的通讯方式和报文的格式。

缺陷

现在的邮件服务器除了25端口外,还采用了其他的默认采用TLS的端口(只能TLS连接)。
但是标准库还会发送STARTTLS命令,但是服务器不会回应,这样就产生了阻塞。
以下是直接通过tls端口发送邮件的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// SendMailTLS not use STARTTLS commond
func SendMailTLS(addr string, auth smtp.Auth, from string, to []string, msg []byte) error {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return err
}
tlsconfig := &tls.Config{ServerName: host}
if err = validateLine(from); err != nil {
return err
}
for _, recp := range to {
if err = validateLine(recp); err != nil {
return err
}
}
conn, err := tls.Dial("tcp", addr, tlsconfig)
if err != nil {
return err
}
defer conn.Close()
c, err := smtp.NewClient(conn, host)
if err != nil {
return err
}
defer c.Close()
if err = c.Hello("localhost"); err != nil {
return err
}
if err = c.Auth(auth); err != nil {
return err
}
if err = c.Mail(from); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}

// validateLine checks to see if a line has CR or LF as per RFC 5321
func validateLine(line string) error {
if strings.ContainsAny(line, "\n\r") {
return errors.New("a line must not contain CR or LF")
}
return nil
}

MIME

多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions)是一个互联网标准,它扩展了电子邮件标准,使其能够支援:
非ASCII字符文本;
非文本格式附件(二进制、声音、图像等);
由多部分(multiple parts)组成的消息体;
包含非ASCII字符的头信息(Header information)。这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。
MIME改善了由RFC 822转变而来的RFC 2822,这些旧标准规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息原本都不能在电子邮件中传输(MIME可以)。MIME规定了用于表示各种各样的数据类型的符号化方法。此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。

基本格式

1
2
3
4
5
6
7
8
9
MIME-Version: 1.0
Content-Type: text/plain
Content-transfer-encoding: base64
boundary = XXXXXXXXXXXXXXXXX
--XXXXXXXXXXXXXXXXX
base64 string
--XXXXXXXXXXXXXXXXX
base64 string

邮件格式

基本字段

1
2
3
4
5
From:来自测试发送<[email protected]>
To:[email protected]
Date:27 Mar 17 00:45 +0800
Cc:[email protected]
Subject: TEST

bcc

密送的实现很好玩,在邮件内容里不填写信息,但是发送的时候发送给密送的那个人。
这里的设计很巧妙。

以上的每一项都以<CRLF>结束,即\r\n

邮件内容

这里使用MIME,当然也可以使用8BITMIME发送多媒体内容。
具体的方式是创建一个MIME part,每个part里面设置自己的Content-DispositionContent-Transfer-EncodingContent-Type
Content-Transfer-Encoding使用base64编码,不然直接发送ascii中含有\r\n.\r\n,邮件就直接结束了。
虽然编码率高了不少,但是简单,易操作,不依赖服务器支持8BITMIME

邮件样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
From:来自测试发送<[email protected]>
To:[email protected]
Date:27 Mar 17 00:45 +0800
Cc:[email protected]
Subject:=?UTF-8?B?5rWL6K+V?=
Content-Type: multipart/mixed; boundary=5b83f06665140150554c5847a8a3b05a5a9d64f5ec6a42fec16a4460223c


MIME-Version: 1.0
--5b83f06665140150554c5847a8a3b05a5a9d64f5ec6a42fec16a4460223c
Content-Transfer-Encoding: base64
Content-Type: text/html

PHA+6L+Z5piv5LiA5bCB5rWL6K+V6YKu5Lu2PC9wPg==
--5b83f06665140150554c5847a8a3b05a5a9d64f5ec6a42fec16a4460223c
Content-Disposition: attachment; filename="=?UTF-8?B?MS50eHQ=?="
Content-Transfer-Encoding: base64
Content-Type: application/application/octet-stream

MS50eHQ=

--5b83f06665140150554c5847a8a3b05a5a9d64f5ec6a42fec16a4460223c
Content-Disposition: attachment; filename="=?UTF-8?B?Mi50eHQ=?="
Content-Transfer-Encoding: base64
Content-Type: application/application/octet-stream

Mi50eHQ=

发送过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
S: 220 xyz.com Simple Mail Transfer Service Ready
C: EHLO foo.com
S: 250 xyz.com is on the air
C: MAIL FROM:<@foo.com:[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK
C: DATA
S: 354 Start mail input; end with <CRLF>.<CRLF>
C: Received: from bar.com by foo.com ; Thu, 21 May 1998
C: 05:33:29 -0700
C: Date: Thu, 21 May 1998 05:33:22 -0700
C: From: John Q. Public <[email protected]>
C: Subject: The Next Meeting of the Board
C: To: [email protected]
C:
C: Bill:
C: The next meeting of the board of directors will be
C: on Tuesday.
C: John.
C: .
S: 250 OK
C: QUIT
S: 221 foo.com Service closing transmission channel

HELO or EHLO

确定服务器可用

MAIL

声明发信邮箱

RCPT

声明收件邮箱。密送的邮箱就是在这里声明,但是不写在邮件内容里面。

DATA

发送邮件的内容。

QUIT

结束发送,并关闭连接。

拓展命令

STARTLTLS

试探服务器是否支持TLS。

8BITMIME

试探服务器是否支持8字长的编码。

其他

其他的命令没有使用,这里挖个坑。

一篇文章从一号拖到现在,真的好丢人啊。 多谢您花费时间阅读我的文章,有不好的地方欢迎指正。

进程标识

每个进程都有一个非负整型表示的唯一进程ID。

  • ID为0的进程通常是调度进程,常常被称为交换进程(swapper)。该进程是内核的一部分,它并不执行任何磁盘上的程序,因此被称为系统进程。
  • 进程ID为1的通常是init进程,在自举过程结束时由内核调用。init进程决不会终止。它是一个普通的用户进程,但它以超级用户特权运行。
  • 进程ID2是页守护进程(page daemon),此进程负责支持虚拟存储器系统的分页操作。
1
2
3
4
5
6
7
8
#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 */

函数fork

1
2
3
4
#include <unistd.h>

pid_t fork(void);
/* 返回值:子进程返回0,父进程返回子进程ID;若出错,返回-1 */

fork创建的新进程被称为子进程(child process)
两次返回的区别是子进程的返回值是0,而父进程的返回值则是新建子进程的进程ID。
子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。父进程和子进程共享正文段。
一般来说,fork之后是父进程先执行还是子进程先执行是不确定的。
在重定向父进程的标准输出时,子进程的标准输出也被重定向。
子进程和父进程共享一个文件偏移量。

函数vfork

父进程和子进程共享数据段,并且先保诚子进程先运行,只有当子进程调用execexit后父进程才可能被调用运行。
调用vfork()后,子程序要么_exit(),要么调用exec(),否则都是未定义行为(UB)

函数exit

5种正常终止方式:

  1. main函数内执行return语句。
  2. 调用exit函数。
  3. 调用_exit_Exit函数。
  4. 进程的最后一个线程在其启动例程中执行return语句。
  5. 进程的最后一个线程调用pthread_exit函数。

3种异常终止:

  1. 调用abort
  2. 当进程接收到某些信号时。
  3. 最后一个线程对“取消”(cancellation)请求作出响应。

对于父进程已经终止的所有进程,它们的父进程都改为init进程,我们称为这些进程由init进程收养。

在UNIX术语中,一个已经终止、但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息、释放它仍占用的资源)的进程被称为僵死进程(zombie)

函数waitwaitpid

当一个进程正常或异常终止时,内核就向其父进程发送SIGCHLD信号。

  • 如果其所有子进程都还在运行,则阻塞。

  • 如果一个子进程终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。

  • 如果没有任何子进程,则立即出错返回。

    1
    2
    3
    4
    5
    #include <sys/wait.h>

    pid_t wait(int *statloc);
    pid_t waitpid(pid_t pid, int *statloc, int options);
    /* 两个函数返回值:若成功,返回进程ID;若出错,返回0或-1 */
  • 在一个子进程终止前,wait使其调用者阻塞,而waitpid有一选项,可使调用者不阻塞。

  • waitpid并不等待在其调用之后的第一个终止子进程,可以控制它所等待的进程。

这两个函数的参数statloc是一个整型指针。如果statloc不是一个空指针,则终止进程的终止状态就存放在它所指向的单元内。

说明
WIFEXITED(status) 若为正常正常终止子进程返回的状态,则为真。对于这种情况可执行WIFEXITED(status),获取子进程传送给exit或_exit参数的低8位
WIFSIGNALED(status) 若为异常终止子进程返回的状态,则为真(接到一个不捕捉的信号)。对于这种情况,可执行WIFSIGNALED(status),则为真(接到一个不捕捉的信号)。对于这种情况,可执行()WTERMSIG(status),获取使子进程终止的信号编号。另外,有些实现(非Single UNIX Specification)定义宏WCOREDUMP(status),若已产生终止进程core文件,则它返回真
WIFSTOPPED(status) 若为当前暂停子进程的返回的状态,则为真。对于这种情况,可执行WSTOPSIG(status),获取使子进程暂停的信号编号
WIFCONTINUED(status) 若在作业控制暂停后已经继续的子进程返回了状态,则为真

waitpid函数中pid参数的作用解释如下:

  • pid == -1 等待任一子进程。此种情况下,waitwaitpid等效。
  • pid > 0 等待进程ID与pid相等的子进程。
  • pid == 0 等待组ID等于调用进程组ID的任一子进程。
  • pid < -1 等待组ID等于pid绝对值的任一子进程。
options常量 说明
WCONTINUED 若实现支持罪业控制,那么由pid制定的任一子进程在停止后已经继续,但其状态尚未报告,则返回其状态
WNOHANG 若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0
WUNTRACED 若某实现支持作业控制,而由pid指定的任一子进程已处于停止状态,并且其状态由停止以来还没报告过,则返回其状态。WIFSTOPPED宏确定返回值是否对应于一个停止的子进程。

函数waittid

1
2
3
4
#include <sys/wait.h>

int waittid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
/* 返回值:若成功,返回0;若出错,返回-1 */
idtype常量 说明
P_PID 等待一特定进程:id包含要等待子进程的进程ID
P_PGID 等待一特定进程组中的任一子进程:id包含要等待子进程的进程组ID
P_ALL 等待任一子进程:忽略id
options常量 说明
WCONTINUED 等待一进程,它以前曾被停止,此后又已继续,但其状态尚未报告
WEXITED 等待已退出的进程
WNOHANG 如无可用的子进程推出状态,立即返回而非阻塞
WNOWAIT 不破坏子进程退出状态。该子进程退出状态可由后续的wait、waitid或waitpid调用取得
WSTOPPED 等待一进程,它已经停止,但其状态尚未报告

函数wait3wait4

1
2
3
4
5
6
7
8
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>

pid_t wait3(int *statloc, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage);
/* 两个函数返回值:若成功,返回进程ID;若出错,返回-1 */

函数exec

调用exec并不创建新进程,所以前后的进程ID并没有改变。exec只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆栈和栈段。

1
2
3
4
5
6
7
8
9
10
11
#include <unistd.h>

int execl(const char *pathname, const char *arg0, ... /* (char *)0 */);
int execv(const char *pathname, char *const argv[]);
int execle(const char *pathname, const char *arg0, ...
/* (char *)0, char *const envp[] */);
int execve(const char *pathname, char *const argv[], char *const envp[]);
int execlp(const char *filename, const char *arg0, ... /* (char *)0 */);
int execvp(const char *filename, char *const argv[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
/* 7个函数返回值:若出错,返回-1;若成功,不返回 */

filename作为参数时:

  • 如果filename中包含/,则将其设为路径名;
  • 否则就按PATH环境变量,在她所指定的各目录搜寻可执行文件。

execl,execle,execlp(结尾带l)要在可变参数结尾添加(char *)0
execlp,execvp(结尾带p)表示第一个参数path不用输入完整路径,只有给出命令名即可,它会在环境变量PATH当中查找命令。
execv,execvp(不带l)表示命令所需的参数以char *arg[]形式给出且arg最后一个元素必须是NULL。

更改用户ID和更改组ID

可以用setuid函数设置实际用户ID和有效用户ID;可以用setgid函数设置实际组ID和有效组ID。

1
2
3
4
5
#include <unistd.h>

int setuid(uid_t uid);
int setgit(gid_t gid);
/* 两个函数返回值:若成功,返回0;若出错,返回-1 */
  1. 若进程拥有超级用户权限,则setuid函数将实际用户ID、有效用户ID以及保存的设置用户ID设置为uid;

  2. 若进程没有超级用户权限,但是uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不更改实际用户ID和保存的设置用户ID;

  3. 若以上两个条件都不满足,则errno设置为EPERM,并返回-1.

  4. 只有超级用户进程可以更改实际用户ID;

  5. 仅当对程序文件设置了设置用户ID位时,exec函数才设置有效用户ID;

  6. 保存的设置用户ID是由ecec复制有效用户ID而得到的。

函数setreuidsetregid

功能是交换实际用户ID和有效用户ID

1
2
3
4
5
#include <unistd.h>

int setreuid(uid_t ruid, uid_t euid);
int setregid(gid_t rgid, gid_t egid);
/* 两个函数的返回值:若成功,返回0;若出错,返回-1 */

如若其中任一参数的值为-1,则表示相应的ID应当保持不变。

函数seteuidsetegid

类似于setuidsetgid,但只更改有效用户ID和有效组ID。

1
2
3
4
5
#include <unistd.h>

int seteuid(uid_t uid);
int setegid(uid_t gid);
/* 两个函数的返回值:若成功,返回0;若出错,返回-1 */

函数system

1
2
3
#include <stdlib.h>

int system(const char *cmdstring);

如果cmdstring是一个空指针,则仅当命令程序可用时,system返回非0值,这一特征可以确定在一个给定的操作系统上是否支持system函数。

  1. fork失败或者waitpid返回处EINTR之外的出错,则system返回-1,并且设置errno以指示错误类型。
  2. 如果exec失败,则返回值如同shell执行了exit(127)一样。
  3. 否则所有3个函数(forkexecwaitpid)都成功,那么system的返回值是shell的终止状态,其格式已在waitpid中说明。

进程会计(process accounting)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
typedef u_short comp_t; /* 3-bit base 8 exponent; 13-bit fraction */
struct acct
{
char ac_flag; /* flag (see Figure 8.26) */
char ac_stat; /* termination status (signal & core flag only) */
/* (Solaris only) */
uid_t ac_uid; /* real user ID */
gid_t ac_gid; /* real group ID */
dev_t ac_tty; /* controlling terminal */
time_t ac_btime; /* starting calendar time */
comp_t ac_utime; /* user CPU time */
comp_t ac_stime; /* system CPU time */
comp_t ac_etime; /* elapsed time */
comp_t ac_mem; /* average memory usage */
comp_t ac_io; /* bytes transferred (by read and write) */
/* "blocks" on BSD systems */
comp_t ac_rw; /* blocks read or written */
/* (not present on BSD systems) */
char ac_comm[8]; /* command name: [8] for Solaris, */
/* [10] for Mac OS X, [16] for FreeBSD, and */
/* [17] for Linux */
};
  1. 我们不能获取永远不终止的进程的会计记录;
  2. 在会计文件记录的顺序对应于进程终止的顺序,而不是它们启动的顺序;
  3. 会计记录对应于进程而不是程序。exec并不创建一个新的会计记录,但相应记录中的命令名称改变了,AFORK标志被清除。

用户标识

得到运行该程序的用户的登录名,当有多个用户名对应着一个用户ID时,通常返回用户登录时用的用户名。

1
2
3
4
#include <unistd.h>

char *getlogin(void);
/* 返回值:若成功,返回指向登陆名字符串的指针;若出错,返回NULL */

进程调度

进程可以通过调整nice值选择以最低优先级运行,只有特权进程允许提高调度权限。
nice值的大小在0(2*NZERO)-1之间,有些实现支持02NZERO。nice值越小,优先级越高*。

1
2
3
4
#include <unistd.h>

int nice(int incr);
/*返回值:若成功,返回新的nice值NZERO;若出错,返回-18*/

getpriority函数可以像nice函数那样用户获取进程的nice值,但是getpriority还可以获取一组相关进程的nice值。

1
2
3
4
#include <sys/resource.h>

int getpriority(int which, id_t who);
/* 返回值:若成功,返回-NZERO~NZERO-1之间的nice值;若出错,返回-1 */

setpriority函数可以用于为进程、进程组和属于特定用户ID的所有进程设置优先级。

1
2
3
4
#include <sys/resource.h>

int setpriority(int which, id_t who, int value);
/* 返回值:若成功,返回0;若出错,返回-1 */

进程时间

times函数获得它自己以及已终止子进程的墙上时钟时间、用户CPU时间和系统CPU时间。

1
2
3
4
#include <sys/times.h>

clock_t times(struct tms *buf);
/* 返回值:若成功,返回墙上时钟时间(以时钟滴答数为单位);若出错,返回-1 */
1
2
3
4
5
6
struct tms {
clock_t tms_utime; /* 用户CPU时间 */
clock_t tms_stime; /* 系统CPU时间 */
clock_t tms_cutime; /* 子进程的用户CPU时间 */
clock_t tms_cstiem; /* 子进程的系统CPU时间 */
}
0%