学习到了 常用函数 system
This commit is contained in:
219
C16-并发/C16-并发.md
Normal file
219
C16-并发/C16-并发.md
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
# 并发
|
||||||
|
|
||||||
|
- 同步
|
||||||
|
- 异步:到来的时刻不确定
|
||||||
|
|
||||||
|
异步事件的处理:
|
||||||
|
|
||||||
|
1. 查询法:事件发生的频率高,查询方式复杂
|
||||||
|
2. 通知法:事件发生的频率低,通知方式简单
|
||||||
|
|
||||||
|
## 信号(初步异步)
|
||||||
|
|
||||||
|
### 信号的概念
|
||||||
|
>
|
||||||
|
> 信号是软件中断。
|
||||||
|
信号的响应依赖于中断。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kill -l # 查看信号列表
|
||||||
|
```
|
||||||
|
|
||||||
|
`core`文件:错误现场的保存。
|
||||||
|
对于个人用户,默认`core`文件大小为0,可通过`ulimit -c`设置。
|
||||||
|
|
||||||
|
### `signal()`函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
typedef void (*sighandler_t)(int);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* signal - 设置信号处理函数
|
||||||
|
* @signum: 信号编号
|
||||||
|
* @handler: 信号处理函数
|
||||||
|
*
|
||||||
|
* 返回值:原信号处理函数
|
||||||
|
*/
|
||||||
|
sighandler_t signal(int signum, sighandler_t handler);
|
||||||
|
|
||||||
|
//* 不使用typedef, 直接声明函数原型
|
||||||
|
void (*signal(int signum,void (*func)(int)))(int);
|
||||||
|
// void (*signal(...)):这表示signal函数的返回类型是一个指向函数的指针,该函数返回类型为void。
|
||||||
|
// (int signum, void (*func)(int)):这是signal函数的参数列表,其中signum是一个整数类型的参数,func是一个指向参数为整数类型、返回类型为void的函数的指针。
|
||||||
|
// (int):这个函数指针所指向的函数接受一个整数类型的参数。
|
||||||
|
```
|
||||||
|
|
||||||
|
**信号会打断阻塞的系统调用。**
|
||||||
|
`write`,`read`,`open`,`fork`等系统调用都可能被信号打断。
|
||||||
|
故要判断返回值是不是`EINTR`,如果是,则表示信号被打断,需要重新调用。
|
||||||
|
|
||||||
|
### 信号的不可靠
|
||||||
|
|
||||||
|
在 Linux 中,信号被用来通知进程发生了某些事件,例如终端用户按下了中断键(Ctrl+C),或者一个进程运行时间过长等。但是信号被称为“不可靠”的,主要是因为以下几个原因:
|
||||||
|
|
||||||
|
1. **丢失信号**:在传统的 Unix 实现中,同一种信号类型如果在处理前多次发生,可能会被合并,只传递一次。这意味着除了第一次之外的其他信号都会被丢弃。例如,如果一个程序几乎同时收到两个 `SIGINT` 信号,它可能只能感知到一个。
|
||||||
|
|
||||||
|
2. **不可预测的顺序**:如果多个不同的信号几乎同时到达,它们被递送到进程的顺序可能与实际发生的顺序不同,这会使得程序的行为难以预测。
|
||||||
|
|
||||||
|
3. **中断系统调用**:在早期的 Unix 系统中,当信号被捕获时,正处于阻塞状态的系统调用(如 read, write, select 等)可能会被中断并提前返回,这常常需要额外的错误处理逻辑来重新发起系统调用。
|
||||||
|
|
||||||
|
4. **异步性**:信号是异步的,这意味着它们可以在程序执行的任何时刻到达。如果信号处理函数(signal handler)不够简单,它可能在执行程序的中间阶段被调用,而此时程序可能处于一个不一致的状态。因此,信号处理函数需要非常小心地编写,通常只能执行异步信号安全的函数。
|
||||||
|
|
||||||
|
为了克服信号的不可靠性,现代操作系统和库引入了新的机制,比如 `sigaction` API 允许更精细的控制信号处理,以及使用 `pselect` 或 `epoll` 等函数的组合来避免系统调用被中断的问题。此外,一些高级语言或框架提供了更高层次的抽象,使得信号处理变得更为安全和可靠。
|
||||||
|
|
||||||
|
### 可重入函数
|
||||||
|
|
||||||
|
所有的系统调用都是可重入的,一部分库函数也是可重入的,比如`memcpy`
|
||||||
|
|
||||||
|
### 信号的响应过程
|
||||||
|
|
||||||
|
每个进程至少两个位图,`mask`和`pending`,一般都是32位的。
|
||||||
|
`mask`是当前进程阻塞的信号集合,`pending`是当前进程收到的信号集合。
|
||||||
|
|
||||||
|
`mask && pending`得到的是当前进程需要处理的信号集合。
|
||||||
|
|
||||||
|
信号从收到到响应有一个不可避免的延迟。
|
||||||
|
|
||||||
|
标准信号的响应没有严格的顺序。
|
||||||
|
|
||||||
|
屏蔽信号就是通过`mask`置位来屏蔽信号。
|
||||||
|
|
||||||
|
M P
|
||||||
|
1 0 常规状态
|
||||||
|
收到信号,未处理
|
||||||
|
1 1
|
||||||
|
从内核态回用户态,M & P = 1,处理信号
|
||||||
|
0 0
|
||||||
|
处理信号前,M和P都置0
|
||||||
|
响应完后,M置1,再次对M & P进行判断。
|
||||||
|
有则重复,无则将M置1,回到常规状态。
|
||||||
|
1 0
|
||||||
|
|
||||||
|
### 常用函数
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* kill - 向进程发送信号
|
||||||
|
* @param: pid: 进程ID:
|
||||||
|
* >0 : 进程ID
|
||||||
|
* =0 : 进程组ID (组内广播)
|
||||||
|
* =-1: 给当前进程有权限发信号的所有进程 (除了init进程)
|
||||||
|
* < -1: 发送给|pid|的进程 (eg. -5 就发送给 5号进程)
|
||||||
|
*
|
||||||
|
* @note:
|
||||||
|
* 这里的pid用法可以联系
|
||||||
|
* pid_t waitpid(int pid, int *status, int options)
|
||||||
|
*
|
||||||
|
* @param: sig: 信号编号
|
||||||
|
* =0 : 不发送信号,error check,用于检测一个进程或者进程组是否存在
|
||||||
|
*
|
||||||
|
* 返回值:成功返回0,失败返回-1并设置errno
|
||||||
|
* errno:
|
||||||
|
* EINVAL : 参数错误
|
||||||
|
* EPERM : 无权限发送信号
|
||||||
|
* ESRCH : 进程不存在
|
||||||
|
*/
|
||||||
|
int kill(pid_t pid, int sig);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* raise - 发送信号给当前进程
|
||||||
|
* @sig: 信号编号
|
||||||
|
*
|
||||||
|
* 返回值:成功返回0,失败返回非零
|
||||||
|
*/
|
||||||
|
int raise(int sig);
|
||||||
|
kill(getpid(), SIGINT); // 等价
|
||||||
|
pthread_kill(pthread_self(), SIGINT); // 多线程等价
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alarm - 设置闹钟
|
||||||
|
* @param: seconds: 闹钟时间,单位为秒
|
||||||
|
*
|
||||||
|
* @note:
|
||||||
|
* - 闹钟时间到时,会发送SIGALRM信号给当前进程。
|
||||||
|
* - 有的平台 sleep 是 alarm + pause 实现的
|
||||||
|
* 这时sleep和alarm在同一个程序中会冲突
|
||||||
|
* - 流量控制的基础
|
||||||
|
*
|
||||||
|
* @eg: 使用单一计时器,构造一组函数,实现任意数量的定时器
|
||||||
|
* 用到 alarm 或 setitimer
|
||||||
|
* TODO
|
||||||
|
*
|
||||||
|
* 返回值:成功返回0,失败返回非零
|
||||||
|
*/
|
||||||
|
unsigned int alarm(unsigned int seconds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pause - 挂起进程
|
||||||
|
*
|
||||||
|
* @note: 挂起进程,直到收到信号或被唤醒
|
||||||
|
*/
|
||||||
|
int pause(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* abort - 终止进程
|
||||||
|
*
|
||||||
|
* @note: 终止进程,立即退出,不执行清理函数,得到core文件
|
||||||
|
*/
|
||||||
|
void abort(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* system - 执行系统命令
|
||||||
|
* @param: command: 命令字符串
|
||||||
|
* @note: 执行系统命令,阻塞当前进程,直到命令执行完毕
|
||||||
|
* ! 需要 block SIGCHLD 并且 ignore SIGINT SIGQUIT
|
||||||
|
* @return: 命令执行的返回值
|
||||||
|
*/
|
||||||
|
int system(const char *command);
|
||||||
|
|
||||||
|
sleep();
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 信号集
|
||||||
|
|
||||||
|
### 信号屏蔽字/`pending`的处理
|
||||||
|
|
||||||
|
### 扩展
|
||||||
|
|
||||||
|
```c
|
||||||
|
sigsuspend();
|
||||||
|
sigaction();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* setitimer - 设置定时器
|
||||||
|
* @param: which: 定时器类型
|
||||||
|
* ITIMER_REAL : 实时定时器
|
||||||
|
* ITIMER_VIRTUAL : 虚拟定时器
|
||||||
|
* ITIMER_PROF : 进程计时器
|
||||||
|
* @param: new_value: 新的定时器值
|
||||||
|
* @param: old_value: 旧的定时器值
|
||||||
|
*
|
||||||
|
* @note: 原子赋值,比 alarm 更精细
|
||||||
|
*
|
||||||
|
* @return:成功返回0,失败返回-1并设置errno
|
||||||
|
*/
|
||||||
|
int setitimer(int which,
|
||||||
|
const struct itimerval *new_value,
|
||||||
|
struct itimerval *old_value);
|
||||||
|
|
||||||
|
// 在it_value之后第一次启动
|
||||||
|
// 后续以it_interval为间隔启动
|
||||||
|
struct itimerval {
|
||||||
|
struct timeval it_interval; /* next value */
|
||||||
|
struct timeval it_value; /* current value */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timeval {
|
||||||
|
time_t tv_sec; /* seconds */
|
||||||
|
suseconds_t tv_usec; /* microseconds */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
```
|
||||||
|
|
||||||
|
### 实时信号
|
||||||
|
|
||||||
|
## 线程(强烈异步)
|
||||||
25
C16-并发/parallel/signal/5sec.c
Normal file
25
C16-并发/parallel/signal/5sec.c
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* @brief 使用time函数实现计时功能
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return int
|
||||||
|
***********************************************************************/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
time_t end;
|
||||||
|
long long count = 0;
|
||||||
|
|
||||||
|
end = time(NULL) + 5;
|
||||||
|
|
||||||
|
while (time(NULL) <= end)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
printf("%lld\n", count);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
35
C16-并发/parallel/signal/5sec_sig.c
Normal file
35
C16-并发/parallel/signal/5sec_sig.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
//!!! 不加volatile关键字,loop变量的值不会被修改,导致死循环!!!
|
||||||
|
static volatile int loop = 1;
|
||||||
|
|
||||||
|
static void alrm_handler(int sig)
|
||||||
|
{
|
||||||
|
loop = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* @brief 用sig实现计时
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return int
|
||||||
|
***********************************************************************/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
long long count = 0;
|
||||||
|
|
||||||
|
//!!!
|
||||||
|
signal(SIGALRM, alrm_handler);
|
||||||
|
alarm(5);
|
||||||
|
//!!! signal注册时钟信号的行为需要在alarm之前
|
||||||
|
|
||||||
|
while (loop)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
printf("%lld \n", count);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
20
C16-并发/parallel/signal/alarm.c
Normal file
20
C16-并发/parallel/signal/alarm.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
alarm(10);
|
||||||
|
alarm(1);
|
||||||
|
alarm(5);
|
||||||
|
|
||||||
|
// alarm(10);
|
||||||
|
// alarm(5);
|
||||||
|
// alarm(1);
|
||||||
|
|
||||||
|
// 效果不一样
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
pause();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
35
C16-并发/parallel/signal/anytimer/Makefile
Normal file
35
C16-并发/parallel/signal/anytimer/Makefile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 方便起见一般都会先定义编译器链接器
|
||||||
|
CC = gcc
|
||||||
|
LD = gcc
|
||||||
|
|
||||||
|
# 正则表达式表示目录下所有.c文件,相当于:SRCS = main.c a.c b.c
|
||||||
|
SRCS = $(wildcard *.c)
|
||||||
|
|
||||||
|
# OBJS表示SRCS中把列表中的.c全部替换为.o,相当于:OBJS = main.o a.o b.o
|
||||||
|
OBJS = $(patsubst %c, %o, $(SRCS))
|
||||||
|
|
||||||
|
# 可执行文件的名字
|
||||||
|
TARGET = main
|
||||||
|
|
||||||
|
# .PHONE伪目标,具体含义百度一下一大堆介绍
|
||||||
|
.PHONY:all clean
|
||||||
|
|
||||||
|
# 要生成的目标文件
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
LDFLAGS=-L/usr/local/lib
|
||||||
|
|
||||||
|
# LDLIBS=-lqueue -lllist
|
||||||
|
|
||||||
|
# 第一行依赖关系:冒号后面为依赖的文件,相当于Hello: main.o a.o b.o
|
||||||
|
# 第二行规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
# 上一句目标文件依赖一大堆.o文件,这句表示所有.o都由相应名字的.c文件自动生成
|
||||||
|
%.o:%.c
|
||||||
|
$(CC) -c $^
|
||||||
|
|
||||||
|
# make clean删除所有.o和目标文件
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET)
|
||||||
0
C16-并发/parallel/signal/anytimer/anytimer.c
Normal file
0
C16-并发/parallel/signal/anytimer/anytimer.c
Normal file
47
C16-并发/parallel/signal/anytimer/anytimer.h
Normal file
47
C16-并发/parallel/signal/anytimer/anytimer.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#ifndef __ANYTIMER__H__
|
||||||
|
#define __ANYTIMER__H__
|
||||||
|
|
||||||
|
#define JOB_MAX 1024
|
||||||
|
typedef void at_jobfunc_t(void *);
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* @brief 创建定时器
|
||||||
|
* @details
|
||||||
|
* @param sec
|
||||||
|
* @param jobp
|
||||||
|
* @param arg
|
||||||
|
* @return int
|
||||||
|
* >= 0 成功,返回定时器ID
|
||||||
|
* == -EINVAL 失败,参数错误
|
||||||
|
* == -ENOMEM 失败,内存不足
|
||||||
|
* == -ENOSPC 失败,数组满
|
||||||
|
********************************************************************/
|
||||||
|
int at_addjob(int sec, at_jobfunc_t *jobp, void *arg);
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* @brief 取消定时器
|
||||||
|
* @details
|
||||||
|
* @param id
|
||||||
|
* @return int
|
||||||
|
* == 0 成功,定时器已取消
|
||||||
|
* == -EINVAL 失败,参数错误
|
||||||
|
* == -EBUSY 失败,指定任务已完成
|
||||||
|
* == -ECANCELED 失败,定时器重复取消
|
||||||
|
********************************************************************/
|
||||||
|
int at_canceljob(int id);
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* @brief 回收任务
|
||||||
|
* @details
|
||||||
|
* @param id
|
||||||
|
* @return int
|
||||||
|
* == 0 成功,任务已回收
|
||||||
|
* == -EINVAL 失败,参数错误
|
||||||
|
********************************************************************/
|
||||||
|
int at_waitjob(int id);
|
||||||
|
|
||||||
|
|
||||||
|
int at_pausejob(int id);
|
||||||
|
int at_resumejob(int id);
|
||||||
|
|
||||||
|
#endif //!__ANYTIMER__H__
|
||||||
40
C16-并发/parallel/signal/anytimer/main.c
Normal file
40
C16-并发/parallel/signal/anytimer/main.c
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include "anytimer.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void f1(void *p)
|
||||||
|
{
|
||||||
|
printf("f1():%s\n", (char *)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void f2(void *p)
|
||||||
|
{
|
||||||
|
printf("f1():%s\n", (char *)p);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int job1;
|
||||||
|
|
||||||
|
puts("Begin!");
|
||||||
|
|
||||||
|
job1 = at_addjob(5, f1, "aaa");
|
||||||
|
if (job1 < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "at_addjob() failed!:%s\n", strerror(-job1));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("End!");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
write(1, ".", 1);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
94
C16-并发/parallel/signal/mycpy.c
Normal file
94
C16-并发/parallel/signal/mycpy.c
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define BUFSIZE 1024
|
||||||
|
/**
|
||||||
|
* 可以用 time 命令找到 BUFSIZE 最佳值
|
||||||
|
*
|
||||||
|
* time ./mycpy /etc/services /tmp/out
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sfd, dfd;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
int len, ret, pos;
|
||||||
|
|
||||||
|
if (argc < 3)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <src> <dst>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do //!!!
|
||||||
|
{
|
||||||
|
sfd = open(argv[1], O_RDONLY);
|
||||||
|
if (sfd < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sfd < 0);
|
||||||
|
|
||||||
|
|
||||||
|
do //!!!
|
||||||
|
{
|
||||||
|
dfd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||||
|
if (dfd < 0)
|
||||||
|
{
|
||||||
|
// !!!
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
close(sfd);
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (dfd < 0);
|
||||||
|
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
len = read(sfd, buf, BUFSIZE);
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror("read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* 可能没写完被别的中断打断 */
|
||||||
|
ret = write(dfd, buf + pos, len);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pos += ret;
|
||||||
|
len -= ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(dfd);
|
||||||
|
close(sfd);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
35
C16-并发/parallel/signal/mytbf/Makefile
Normal file
35
C16-并发/parallel/signal/mytbf/Makefile
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# 方便起见一般都会先定义编译器链接器
|
||||||
|
CC = gcc
|
||||||
|
LD = gcc
|
||||||
|
|
||||||
|
# 正则表达式表示目录下所有.c文件,相当于:SRCS = main.c a.c b.c
|
||||||
|
SRCS = $(wildcard *.c)
|
||||||
|
|
||||||
|
# OBJS表示SRCS中把列表中的.c全部替换为.o,相当于:OBJS = main.o a.o b.o
|
||||||
|
OBJS = $(patsubst %c, %o, $(SRCS))
|
||||||
|
|
||||||
|
# 可执行文件的名字
|
||||||
|
TARGET = main
|
||||||
|
|
||||||
|
# .PHONE伪目标,具体含义百度一下一大堆介绍
|
||||||
|
.PHONY:all clean
|
||||||
|
|
||||||
|
# 要生成的目标文件
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
LDFLAGS=-L/usr/local/lib
|
||||||
|
|
||||||
|
# LDLIBS=-lqueue -lllist
|
||||||
|
|
||||||
|
# 第一行依赖关系:冒号后面为依赖的文件,相当于Hello: main.o a.o b.o
|
||||||
|
# 第二行规则:$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
# 上一句目标文件依赖一大堆.o文件,这句表示所有.o都由相应名字的.c文件自动生成
|
||||||
|
%.o:%.c
|
||||||
|
$(CC) -c $^
|
||||||
|
|
||||||
|
# make clean删除所有.o和目标文件
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET)
|
||||||
99
C16-并发/parallel/signal/mytbf/main.c
Normal file
99
C16-并发/parallel/signal/mytbf/main.c
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "mytbf.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define CPS 10
|
||||||
|
#define BUFSIZE 1024
|
||||||
|
#define BURST 100 //!! token上限
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sfd, dfd = 1;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
int len, ret, pos;
|
||||||
|
int size;
|
||||||
|
mytbf_t *tbf;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <src>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbf = mytbf_init(CPS, BURST);
|
||||||
|
if (NULL == tbf)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "mytbf_init failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do //!!!
|
||||||
|
{
|
||||||
|
sfd = open(argv[1], O_RDONLY);
|
||||||
|
if (sfd < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sfd < 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
size = mytbf_fetchtoken(tbf, BUFSIZE);
|
||||||
|
if (size < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "mytbf_fetchtoken failed: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
//* 阻塞在这里的时候,token会自增
|
||||||
|
while ((len = read(sfd, buf, size)) < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror("read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (size - len > 0)
|
||||||
|
mytbf_returntoken(tbf, size - len);
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* 可能没写完被别的中断打断 */
|
||||||
|
ret = write(dfd, buf + pos, len);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pos += ret;
|
||||||
|
len -= ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleep(1); //! 能实现,但是移植性不好
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sfd);
|
||||||
|
mytbf_destroy(tbf);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
155
C16-并发/parallel/signal/mytbf/mytbf.c
Normal file
155
C16-并发/parallel/signal/mytbf/mytbf.c
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* @file mytbf.c
|
||||||
|
* @brief
|
||||||
|
* 令牌桶库实现
|
||||||
|
*
|
||||||
|
* @author lzy (lllzzzyyy@buaa.edu.cn)
|
||||||
|
* @url https://lzyyyyyy.fun
|
||||||
|
*
|
||||||
|
* @date 2024-05-26
|
||||||
|
*
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include "mytbf.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct mytbf_st
|
||||||
|
{
|
||||||
|
int cps;
|
||||||
|
int burst;
|
||||||
|
int token;
|
||||||
|
int pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mytbf_st *job[MYTBF_MAX];
|
||||||
|
static int inited = 0;
|
||||||
|
static __sighandler_t alrm_handler_save; //!!! 保存原来的alarm行为
|
||||||
|
|
||||||
|
|
||||||
|
static int get_free_pos()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < MYTBF_MAX; i++)
|
||||||
|
{
|
||||||
|
if (NULL == job[i])
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alrm_handler(int s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
alarm(1);
|
||||||
|
|
||||||
|
for (i = 0; i < MYTBF_MAX; i++)
|
||||||
|
{
|
||||||
|
if (NULL != job[i])
|
||||||
|
{
|
||||||
|
job[i]->token += job[i]->cps;
|
||||||
|
if (job[i]->token > job[i]->burst)
|
||||||
|
job[i]->token = job[i]->burst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void module_unload()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
signal(SIGALRM, alrm_handler_save);
|
||||||
|
alarm(0);
|
||||||
|
for (i = 0; i < MYTBF_MAX; i++)
|
||||||
|
free(job[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void module_load()
|
||||||
|
{
|
||||||
|
alrm_handler_save = signal(SIGALRM, alrm_handler);
|
||||||
|
alarm(1);
|
||||||
|
|
||||||
|
atexit(module_unload); //!!! atexit()
|
||||||
|
}
|
||||||
|
|
||||||
|
mytbf_t *mytbf_init(int cps, int burst)
|
||||||
|
{
|
||||||
|
struct mytbf_st *me;
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
if (!inited)
|
||||||
|
{
|
||||||
|
module_load();
|
||||||
|
inited = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = get_free_pos();
|
||||||
|
if (pos < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
me = malloc(sizeof(*me));
|
||||||
|
if (NULL == me)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
me->cps = cps;
|
||||||
|
me->burst = burst;
|
||||||
|
me->token = 0;
|
||||||
|
me->pos = pos;
|
||||||
|
|
||||||
|
job[pos] = me;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int min(int a, int b)
|
||||||
|
{
|
||||||
|
return a < b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mytbf_fetchtoken(mytbf_t *ptr, int size)
|
||||||
|
{
|
||||||
|
if (size <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
struct mytbf_st *me = ptr;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while (me->token <= 0)
|
||||||
|
pause();
|
||||||
|
|
||||||
|
n = min(size, me->token);
|
||||||
|
|
||||||
|
me->token -= n;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mytbf_returntoken(mytbf_t *ptr, int size)
|
||||||
|
{
|
||||||
|
if (size <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
struct mytbf_st *me = ptr;
|
||||||
|
|
||||||
|
me->token += size;
|
||||||
|
if (me->token > me->burst)
|
||||||
|
me->token = me->burst;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mytbf_destroy(mytbf_t *ptr)
|
||||||
|
{
|
||||||
|
struct mytbf_st *me = ptr;
|
||||||
|
|
||||||
|
job[me->pos] = NULL;
|
||||||
|
|
||||||
|
free(ptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
26
C16-并发/parallel/signal/mytbf/mytbf.h
Normal file
26
C16-并发/parallel/signal/mytbf/mytbf.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
* @file mytbf.h
|
||||||
|
* @brief
|
||||||
|
* 令牌桶库
|
||||||
|
*
|
||||||
|
* @author lzy (lllzzzyyy@buaa.edu.cn)
|
||||||
|
* @url https://lzyyyyyy.fun
|
||||||
|
*
|
||||||
|
* @date 2024-05-26
|
||||||
|
*
|
||||||
|
***********************************************************************/
|
||||||
|
#ifndef __MYTBF__H__
|
||||||
|
#define __MYTBF__H__
|
||||||
|
|
||||||
|
#define MYTBF_MAX 1024
|
||||||
|
typedef void mytbf_t;
|
||||||
|
|
||||||
|
mytbf_t *mytbf_init(int cps, int burst);
|
||||||
|
|
||||||
|
int mytbf_fetchtoken(mytbf_t *, int);
|
||||||
|
|
||||||
|
int mytbf_returntoken(mytbf_t *, int);
|
||||||
|
|
||||||
|
int mytbf_destroy(mytbf_t *);
|
||||||
|
|
||||||
|
#endif //!__MYTBF__H__
|
||||||
108
C16-并发/parallel/signal/slowcat.c
Normal file
108
C16-并发/parallel/signal/slowcat.c
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define CPS 10
|
||||||
|
#define BUFSIZE CPS
|
||||||
|
|
||||||
|
static volatile int loop = 0;
|
||||||
|
|
||||||
|
static void alrm_handler(int s)
|
||||||
|
{
|
||||||
|
// alarm(1); //!! 产生新的alarm
|
||||||
|
loop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* @brief slowcat
|
||||||
|
* @details 流量控制,漏筒实现
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return int
|
||||||
|
***********************************************************************/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sfd, dfd = 1;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
int len, ret, pos;
|
||||||
|
struct itimerval itv;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <src>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGALRM, alrm_handler);
|
||||||
|
// alarm(1);
|
||||||
|
|
||||||
|
itv.it_interval.tv_sec = 1;
|
||||||
|
itv.it_interval.tv_usec = 0;
|
||||||
|
itv.it_value.tv_sec = 1;
|
||||||
|
itv.it_value.tv_usec = 0;
|
||||||
|
if (setitimer(ITIMER_REAL, &itv, NULL) < 0)
|
||||||
|
{
|
||||||
|
perror("setitimer");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do //!!!
|
||||||
|
{
|
||||||
|
sfd = open(argv[1], O_RDONLY);
|
||||||
|
if (sfd < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sfd < 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
while (!loop)
|
||||||
|
pause(); //!
|
||||||
|
loop = 0;
|
||||||
|
|
||||||
|
while ((len = read(sfd, buf, BUFSIZE)) < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror("read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* 可能没写完被别的中断打断 */
|
||||||
|
ret = write(dfd, buf + pos, len);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pos += ret;
|
||||||
|
len -= ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleep(1); //! 能实现,但是移植性不好
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sfd);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
102
C16-并发/parallel/signal/slowcat2.c
Normal file
102
C16-并发/parallel/signal/slowcat2.c
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define CPS 10
|
||||||
|
#define BUFSIZE CPS
|
||||||
|
#define BURST 100 //!! token上限
|
||||||
|
|
||||||
|
// static volatile int token = 0;
|
||||||
|
static volatile sig_atomic_t token = 0; //!!! 保证原子
|
||||||
|
|
||||||
|
static void alrm_handler(int s)
|
||||||
|
{
|
||||||
|
alarm(1); //!! 产生新的alarm
|
||||||
|
token++;
|
||||||
|
if (token > BURST)
|
||||||
|
token = BURST;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* @brief slowcat
|
||||||
|
* @details 流量控制,令牌桶实现
|
||||||
|
* @param argc
|
||||||
|
* @param argv
|
||||||
|
* @return int
|
||||||
|
***********************************************************************/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sfd, dfd = 1;
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
int len, ret, pos;
|
||||||
|
|
||||||
|
if (argc < 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s <src>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
signal(SIGALRM, alrm_handler);
|
||||||
|
alarm(1);
|
||||||
|
|
||||||
|
do //!!!
|
||||||
|
{
|
||||||
|
sfd = open(argv[1], O_RDONLY);
|
||||||
|
if (sfd < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (errno != EINTR)
|
||||||
|
{
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sfd < 0);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
while (token <= 0)
|
||||||
|
pause(); //!
|
||||||
|
|
||||||
|
token--; //!!! 这条指令不一定原子
|
||||||
|
|
||||||
|
//* 阻塞在这里的时候,token会自增
|
||||||
|
while ((len = read(sfd, buf, BUFSIZE)) < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
perror("read");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
pos = 0;
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
/* 可能没写完被别的中断打断 */
|
||||||
|
ret = write(dfd, buf + pos, len);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
//!!!
|
||||||
|
if (EINTR == errno)
|
||||||
|
continue;
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
pos += ret;
|
||||||
|
len -= ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleep(1); //! 能实现,但是移植性不好
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sfd);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
26
C16-并发/parallel/signal/star.c
Normal file
26
C16-并发/parallel/signal/star.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static void int_hander(int s)
|
||||||
|
{
|
||||||
|
write(1, "!", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
//* ignore SIGINT
|
||||||
|
// signal(SIGINT, SIG_IGN);
|
||||||
|
|
||||||
|
signal(SIGINT, int_hander);
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
write(1, "*", 1);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user