几何大杂烩
该文章主要会写一些图形学相关内容。
将下图中v⃗\Large\vec{v}v分解为n⃗\Large\vec{n}n方向的投影a⃗\Large\vec{a}a,以及垂直分量b⃗\Large\vec{b}b。
v⃗,e⃗,α\Large\vec{v},\vec{e},\alphav,e,α都是已知的量,
cosα=∣a⃗∣∣v⃗∣\Large \cos{\alpha}=\frac{|\vec{a}|}{|\vec{v}|}cosα=∣v∣∣a∣;
∣a⃗∣=∣v⃗∣cosα\Large |\vec{a}|=|\vec{v}|\cos{\alpha}∣a∣=∣v∣cosα;
a⃗=n⃗∣a⃗∣∣n⃗∣=n⃗∣v⃗∣cosα∣n⃗∣=n⃗∣n⃗∣∣v⃗∣cosα∣n⃗∣2=n⃗n⃗v⃗∣n⃗∣2\Large \vec{a}=\vec{n}\frac{|\vec{a}|}{|\vec{n}|}=\vec{n}\frac{|\vec{v}|\cos{\alpha}}{|\vec{n}|}=\vec{n}\frac{|\vec{n}||\vec{v}|\cos{\alpha}}{|\ve ...
利用C实现C++的多态
为了简化,只考虑有虚函数的单继承的情况。
假如想在C中实现以下在C++中的代码,应该如何做呢?
1234567891011121314151617181920212223242526class Base {public: int x; virtual ~Base() = default; void baseFunc(); virtual void vfunc1(); virtual void vfunc2();};void Base::baseFunc() { printf("This is Base::baseFunc(no virtual), x = %d\n", x); }void Base::vfunc1() { printf("This is Base::vfunc1(virtual), x = %d\n", x); }void Base::vfunc2() { printf("This is Base::vfunc2(virtual), x ...
IPC的几种方式
每个操作系统都有自己的进程间通信的方式,不过大都类似,这里主要讨论Linux下的几种进程间通信方式。
管道
大多数操作系统的管道是半双工的,某些系统有全双工管道。管道只能在具有公共祖先的两个进程中使用,通常有一个进程创建,另一个进程被fork出来,此时这两个进程就可以使用该管道。
在命令行中会以|的形式将两边程序进行管道通信,例如
1ps aux | grep s | wc
在程序中,管道可以通过pipe函数进行创建
12345#include <unistd.h>// fd[0]是管道的读口,f[1]是管道的写口// 如果创建成功返回0,否则返回-1int pipe(int fd[2]);
为了不混淆两个进程谁来读或谁来写,一般会创建一个管道,fork之后,父进程关闭一端,子进程关闭另一端,这样就形成了一个单向流动的管道。
具体用法
1234567891011121314151617181920212223242526272829303132333435363738394041#include <unistd.h>#include <wait.h&g ...
数据库事务并发控制
事务四大性质(ACID)
原子性(atomicity):事物的所有操作在数据库中要么全部正确反映出来,要么完全不反映。
一致性(consistency):执行隔离事务时保持数据库的一致性。
隔离性(isolation):尽管多个事务可能并发执行,但系统保证,对于任一一对事务,两者之间都感受不到系统中有其他事务在并发执行。
持久性(durability):一个事务完成后,它对数据库的改变必须是永久的,即使系统出现故障。
可串行化
考虑下面一个调度
T1
T2
read(A)read(A)read(A)
write(A)write(A)write(A)
read(A)read(A)read(A)
write(A)write(A)write(A)
read(B)read(B)read(B)
write(B)write(B)write(B)
read(B)read(B)read(B)
write(B)write(B)write(B)
该调度中T1的write(A)指令与T2的read(A)指令冲突,因为如果交换 ...
CMU15-445 Project
该课程主要实现一个单机数据库,支持基本的SQL操作,并且实现了并发控制。每年秋季会出新的project,内容可能会有些区别,像2020年需要实现一个B+ Tree,而2021年实现的是Hash Index。对于外校的人,课程提供了project的提交网站,有非常大的帮助。
课程主页:CMU 15-445/645 :: Intro to Database Systems (Fall 2021)
Project1
Task1 - LRU REPLACEMENT POLICY
目标
实现一个LRU Replacer,用来跟踪页面使用情况,并采取LRU替换策略。主要跟后面的Buffer Pool配合使用。
实验已经给了LRUReplacer类,主要需要完成三个函数:
bool Victim(frame_id_t *frame_id):删除一个最近最久未使用的页面。
void Pin(frame_id_t frame_id):被Pin的frame说明正在被引用,需要将该frame从Replacer中删除。
void Unpin(frame_id_t frame_id):当frame的pin_c ...
MIT6.824Lab
Lab1
MapReduce的工作流程
整个Lab1的目标基本上就是实现这张图上的功能。
在已有的代码里已经提供好了一些map和reduce方法,我们要做的就是通过一个Coordinator来给多个Worker分配任务,每个Worker执行一个map或reduce任务。
那么该如何在Coordinator和Worker之间进行信息的交流?这里有很多种方法,因为这是在本地执行,所以可以利用共享内存、管道等进程间通信方式来实现。而对于跨机器的进程,可以使用RPC来远程调用方法,恰好Lab里提供了RPC的使用方法。
大致思路如下:
Coordinator里有GetTask和FinishedTask方法,Worker会一直循环通过RPC调用这两个方法来获取任务和通知任务完成,根据获取到的不同任务类型执行不同方法,直到所有任务做完。
Worker里有两个主要函数performMap和performReduce分别用来执行map和reduce任务。
由于需要知道任务的一些信息,所以我需要在GetTask和FinishedTask的参数类型中进行定义。
1234567891011121314151 ...
网络编程(四)
多进程服务端
并发服务器端的实现方法
多进程服务器:通过创建多个进程提供服务。
多路复用服务器:通过捆绑并统一管理I/O对象提供服务。
多线程服务器:通过生成与客户端等量的线程提供服务。
fork函数创建进程
1234#include <unistd.h>// 成功返回进程ID,失败返回-1pid_t fork(void);
fork函数将创建调用的进程副本。并非根据完全不同的程序创建进程,而是复制正在运行的、调用fork函数的进程。两个进程都将执行fork函数调用后的语句。因为通过同一个进程、复制相同的内存空间,之后的程序流要根据fork函数的返回值加以区分。
父进程:fork函数返回子进程ID。
子进程:fork函数返回0。
僵尸进程及产生原因
进程在执行完main函数中的程序后应该被销毁,但有时这些进程变成僵尸进程,占用系统中的重要资源。这种状态下的进程被称作“僵尸进程”。
调用fork函数产生子进程的终止方式:
传递参数并调用exit函数。
main函数中执行return语句并返回值。
向exit函数传递的参数值和main函数的return语句返回的值都 ...
网络编程(三)
什么是域名
DNS是对IP地址和域名进行互相转换的系统,其核心是DNS服务器。
提供网络服务的服务器端也是通过IP地址区分的,但几乎不可能以非常难记的IP地址形式交换服务器端地址信息。因此,将容易记的域名分配并取代IP地址。
DNS服务器
所有计算机中都记录着默认DNS服务器地址,就是通过这个默认DNS服务器得到相应域名的IP地址信息。在浏览器地址栏中输入域名后,浏览器通过默认DNS服务器获取该域名对应的IP地址,之后才真正进入该网站。
在Linux下可以使用nslookup命令,进一步输入信息,获得默认DNS服务器地址。
计算机内置的默认DNS服务器并不知道网络上所有域名的IP地址信息,此时会向其他DNS服务器询问,并提供给用户。
利用域名获取IP地址
12345678910111213#include <netdb.h>// 成功时返回hostnet结构体地址,失败返回NULL指针struct hostent* gethostbyname(const char* hostname);// hostnet 结构体定义struct hostent { char* ...
网络编程(二)
表示IPv4地址的结构体
123456struct sockaddr_in { sa_family_t sin_family; // 地址族(Address Family) uint16_t sin_port; // 16位TCP/UDP端口号 struct in_addr sin_addr; // 32位IP地址 char sin_zero[8]; // 不使用};
其中的struct in_addr里面为一个32位整型
123struct in_addr { In_addr_t s_addr; // 32位IPv4地址};
sockaddr_in的成员分析
sin_family
地址族
含义
AF_INET
IPv4网络协议中使用的地址族
AF_INET6
IPv6网络协议中使用的地址族
AF_LOCAL
本地通信中采用的UNIX协议的地址族
sin_port
保存16位端口号,且以网络字节序保存。
sin_addr
保存32位IP地址信息,也以网络字节 ...
网络编程(一)
socket函数声明
123456#include <sys/socket.h>// domain 套接字中使用的协议族信息// type 套接字数据传输类型信息// protocol 计算机间通信中使用的协议信息int socket(int domain, int type, int protocol);
协议族(Protocol Family)
socket函数的第一个参数
名称
协议族
PF_INET
IPv4互联网协议族
PF_INET6
IPv6互联网协议族
PF_LOCAL
本地通信的UNIX协议族
PF_PACKET
底层套接字的协议族
PF_IPX
IPX Novell协议族
套接字类型(Type)
socket函数的第二个参数
类型1:面向连接的套接字(SOCK_STREAM)
特点:
传输过程中数据不会消失。
按序传输数据。
传输的数据不存在数据边界。
类型2:面向消息的套接字(SOCK_DGRAM)
特点:
强调快速传输而非传输顺序。
传输的数据可能丢失也可能损毁。
传输的数据有数据边界。
限制每次 ...