管道
# mkfifo fifo
# echo 要写入的数据 > fifo
# cat fifo
# 管道本身不存储数据。可以当成水管来理解
# 水桶(文件)才是存放数据的容器
# 水管是负责运输,并且一根水管不可能同时做到往水桶里加水和取水
| 步骤 | 进程A | 函数 | 进程B | 步骤 |
|---|---|---|---|---|
| 1 | 创建管道 | mkfifo | ---- | |
| 2 | 打开管道 | open | 打开管道 | 1 |
| 3 | 读写管道 | read/write | 读写管道 | 2 |
| 4 | 关闭管道 | close | 关闭管道 | 3 |
| 5 | 删除管道 | unlink |
#include <unistd.h>
int pipe(int pipefd[2]);
//成功返回0 失败返回-1
pipefd[2] 作为输出参数
编程步骤:
内存映射(mmap)
#include <sys/mman.h>
//虚拟内存映射到物理内存或者文件
void *mmap(
void *addr, //虚拟内存起始位置,如果为NULL则系统自动选定合适的虚拟内存,成功则返回 一般给NULL
size_t length, //映射长度,以字节为单位,自动按照(4K)页对齐
int prot, //映射权限
int flags, //映射标志
int fd, //文件描述符,如果映射到文件则需要指定 如果不是映射到文件(匿名映射)则给0即可
off_t offset //文件偏移量,自动按照页(4k)对齐
);
/*
成功返回映射区内存的起地址,失败返回-1 (MAP_FAILED)
prot 权限取值:
PROT_EXEC - 映射区可执行
PROT_READ - 映射区可读
PROT_WRITE - 映射区可写
PROT_NONE - 映射区不可访问
如果既需要读,也需要写,则 PROT_READ|PROT_WRITE
flags 映射标志:
MAP_FIXED - 若在addr内存地址上无法创建映射,则失败(无此标志系统会自动调整合适位置)
MAP_SHARED - 对映射区域的写入操作直接写入到文件中
MAP_PRIVATE - 对映射区的写入操作只写入到缓冲区中,不会真正写入到文件
MAP_ANONYMOUS - 匿名映射 将虚拟内存映射到物理内存而非文件 忽略fd 和 offset参数
MAP_DENYWRITE - 拒绝其它对文件的写入操作
MAP_LOCKED - 锁定映射区域,保证其不被置换
一定需要 MAP_SHARED 和 MAP_PRIVATE 二选一
*/
//取消内存映射
int munmap(void *addr,size_t length);
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname,int pro_id);
pathname - 一个真实存在的文件或者目录的路径名
pro_id - 项目ID,低8位有效,其值域[0,255]
成功返回键值,失败返回-1
注意:起作用的是pathname参数所表示的路径,而非pathname字符串本身
共享内存
#include <sys/types.h>
#include <sys/shm.h>
//1.创建/获取共享内存 内核维护
int shmget(key_t key,size_t size,int shmflg);
/*
A.以参数key作为键值创建共享内存,如果共享内存已经存在,则获取该共享内存
B.size参数指定共享内存的大小(单位字节),建议取4096的整数倍
若希望创建共享内存,则必须指定size参数
若只是获取已有的共享内存,则size参数可以传递0
C.参数shmflg标识
0 - 获取,如果共享内存不存在则获取失败
IPC_CREAT - 创建,不存在则创建 存在则获取(除非指定IPC_EXCL)
如果IPC_CREAT需要给定共享内存的权限(mode) IPC_CREAT|0644
IPC_EXCL - 排斥,和IPC_CREAT按位域,如果共享内存已经存在则失败
成功返回共享内存的标识,失败返回-1
*/
//2.加载共享内存 将进程中的虚拟内存地址映射到共享内存中
void* shmat(int shmid,void *shmaddr,int shmflg);
/*
A.将shmid(shmget的返回值)参数所标识的共享内存,映射到调用进程的地址空间
B.可以通过参数shmaddr(进程中的虚拟地址)人为指定映射地址,也可以将参数置为NULL,由系统自动选择
C.参数shmflg标识:
0 - 以读写方式使用共享内存
SHM_RDONLY - 以只读方式使用共享内存
SHM_RND - 只在shmaddr参数非NULL时才起作用,表示对shmaddr参数向下取内存页的整数倍作为映射地址
成功返回映射地址,失败返回-1(0XFFFFFFF)
如果加载成功,内核将该共享内存的加载计数加1(共享内存由内核维护,记录有多少个进程加载了该共享内存)
*/
//3.卸载共享内存
int shmdt(const void *shmaddr);
/*
将参数shmaddr所指向加载的共享内存映射从调用进程的取消映射
成功返回0,失败返回-1
如果卸载成功,内核会将该共享内存的加载计数减1
*/
//4.销毁/控制共享内存
int shmctl(int shmid,int cmd,struct shmid_ds* buf);
/*
A.参数shmid是shmget的返回值 是对shmid所标识的共享内存进行删除/获取共享内存的信息
B.cmd取值
IPC_STAT - 获取共享内存的属性,通过buf参数输出
IPC_SET - 设置共享内存的属性,通过buf参数输入,仅三个属性可设置
shm_perm.uid 用户ID
shm_perm.gid 组ID
shm_perm.mode 权限
IPC_RMID - 标记删除共享内存
并非真正删除共享内存,只是做一个删除标记,禁止其被继续加载,但已有加载依然保留。
只有当该共享内存的加载计数为0且使用IPC_RMID时才真正被删除
成功返回0 失败返回-1
*/
struct shmid_ds{
struct ipc_perm shm_perm; //所有者及权限
size_t shm_segsz; //共享内存大小(以字节为单位)
time_t shm_atime; //最后加载时间
time_t shm_dtime; //最后卸载时间
time_t shm_ctime; //最后修改时间
pid_t shm_cpid; //创建共享内存的进程ID
pid_t shm_lpid; //最后加载、卸载进程的ID
shmatt_t shm_nattch; //当前加载计数
...
};
struct ipc_perm{
key_t __key; //键值
uid_t uid; //有效属主ID
gid_t gid; //有效属组ID
uid_t cuid; //有效创建者ID
gid_t cgid; //有效创建组ID
unsigned short mode; //权限
unsigned short __seq;//序列号
};
#ipcs -m #查看当前系统的共享内存
#ipcrm -m shmid #删除指定的共享内存
消息队列
#include <sys/msg.h>
//msgget 创建或者获取消息队列
int msgget(key_t key,int msgflg);
/*
A.该函数以参数key作为键值创建消息队列,如果存在则获取消息队列
B.msgflg标识
0 - 获取,不存在即失败
IPC_CREAT - 创建,不存在则创建,已存在则获取,除非 创建时需要给定权限 IPC|0644
IPC_EXCL - 排斥,创建时如果已经存在则创建失败
成功返回消息队列标识,失败返回-1
*/
//msgsnd向消息队列发送消息
int msgsnd(int msgqid,const void *msgp,size_t msgsz,int msgflg);
/*
A. msgqid 消息队列的标识 msgget函数的返回值
B. msgp参数是一个指针,指针指向一块内存,内存中包含消息类型和消息数据
内存中的前4/8个字节必须是一个大于0的整数,代表消息类型,其后紧跟消息数据
消息数据的字节长度用msgsz参数表示 注意:msgsz长度并不包含消息类型4/8个字节
+------------+--------------------+
msgp--> |消息类型(>0) | 消息数据 |
+------------+--------------------+
|<-4/8Byte-> |<----msgsz--------->|
C.若内核中消息队列缓冲区有足够的空闲空间,则此函数会将消息拷入缓冲区并立即返回0,表示发送成功,否则此函数会阻塞,直到内核中的消息队列缓冲区有足够的空闲空间为止(比如有消息被接收)
D.若msgflg参数包含IPC_NOWAIT位,则当内核中的消息队列没有足够空闲空间时,此函数不会阻塞,而是直接返回-1,且errno设置为EAGAIN
成功返回0 失败返回-1
*/
//msgrcv 从消息队列中接收消息
ssize_t msgrcv(int msgqid,void *msgp,size_t msgsz,long msgtype,int msgflg);
/*
A.msgqid 消息队列标识,msgget函数的返回值
B.msgp指针指向一个包含消息类型(4byte)和消息数据的内存块,用于存储消息类型和消息数据本身
C.msgsz参数用来标明消息数据缓冲区字节大小 msgp指针指向的内存块的大小-4/8byte
D.若所接收到的消息字节数据大于msgsz参数,即消息太长
E.如果msgflg参数中包含MSG_NOERROR位,则消息太长会被截取msgsz字节返回,剩余部分会被丢弃
如果msgflg参数不包含MSG_NOERROR五个,消息太长时,不会对该消息做任何处理,直接返回-1,且errno设置为E2BIG
F.msgtype参数表示期望接收哪类消息
msgtype = 0 - 返回消息队列中的第一条消息
msgtype > 0 - 若msgflg参数不包含MSG_EXCEPT位,则返回消息队列中第一个类型为msgtype的消息
如果msgflg参数包含MSG_EXCEPT位,则返回消息队列中第一个消息类型不为msgtype的消息
msgtype < 0 - 返回消息队列中类型小于等于msgtype绝对值的消息
如果有多条消息满足,则返回消息类型最小的第一条消息
G.若消息队列中有可接收的消息,则此函数会将该消息移出消息队列拷贝到msgp内存中并立即返回0,表示接收成功
如果消息队列中没有可接收的消息,则此函数会阻塞,直到消息队列中有可接收的消息为止
H.如果msgflg参数包含IPC_NOWAIT位,则当消息队列中没有可接收的消息时(没有满足要求的消息),则此函数不会阻塞,而是返回-1,设置errno为ENOMSG
成功返回所接收到消息数据的字节数,失败返回-1
*/
//msgctl销毁/控制消息队列
int msgctl(int msgqid,int cmd,struct smqid_ds *buf);
/*
cmd的取值:
IPC_STAT - 获取消队列的属性,通过buf参数输出
IPC_SET - 设置消息队列的属性,通过buf输入
msg_perm.uid
msg_perm.gid
msg_perm.mode
msg_qbytes
IPC_RMID - 立即删除消息队列
此时所有阻塞在该消息队列的,msgsnd/msgrcv函数调用都会立即返回失败,errno设置为EIDRM
成功返回0 失败返回-1
*/
struct msqid_ds{
struct ipc_perm msg_perm; //权限依赖
time_t msg_stime; //最后发送时间
time_t msg_rtime; //最后接收时间
time_t msg_ctime; //最后修改时间
unsigned long _msg_cbytes; //消息队列中的字节数
msgqumt_t msg_qnum; //消息队列中消息数
msglen_t msg_qbytes; //消息队列能容纳的最大字节数
pid_t msg_lspid; //最后发送消息进程ID
pid_t msg_lrpid; //最后接收消息进程ID
};
struct ipc_perm{
key_t __key; //键值
uid_t uid; //有效属主ID
gid_t gid; //有效属组ID
uid_t cuid; //有效创建者ID
gid_t cgid; //有效创建组ID
unsigned short mode; //权限
unsigned short __seq;//序列号
};
#ipcs -q # 查看消息队列
#ipcrm -q msqid # 删除指定的消息队列
信号量
#include <sys/sem.h>
//semget 创建/获取信号量集 信号量数组
int semget(key_t key,int nsems,int semflg);
/*
该函数是以key作为键值创建一个信号量集合(nsems参数表示集合中信号量的数量),如果是获取已经存在的信号量集合则nsems可以取0
semflg取值:
0 - 获取,不存在则失败
IPC_CREAT - 创建,不存在则创建,存在即获取,除非IPC_EXCL
IPC_EXCL - 排斥,和IPC_CREAT一起使用,如果信号量集合存在则失败
成功返回信号量集合标识,失败返回-1
*/
//semop 操作信号量/信号量集合
int semop(int semid,struct sembuf *sops,unsigned nsops);
/*
semid参数是信号量集合的标识,semget函数的返回值
sops: 其实是一个数组的首地址 如果只有一个元素时,可以是一个元素的首地址
nsops:数组长度
sops数组中每个元素都是stuct sembuf的数据 执行操作如下:
若sem_op大于0,则将其加到sem_num下标所表示的信号量的计数值上,以表示对资源的释放
若sem_op小于0,则将其从sem_num下标所表示的信号量减去sem_op的绝对值,以表示对资源的获取
若sem_num信号量的计数值不够减(信号量数值不能为负),则此函数会阻塞,直到该信号量够减为止,以表示对资源的等待;
若sem_flg包含IPC_NOWAIT,则当sem_num信号量计数值不够减时,此函数不会阻塞,而是返回-1,errno设置为EAGAIN,以便在等待资源的同时还可以做其它处理
若sem_op等于0,则直到sem_num所表示的信号量的计数值为0时才返回,除非sem_flg包含IPC_NOWAIT
成功返回0,失败返回-1
*/
struct sembuf{
unsigned short sem_num; //信号量下标 下标从0开始,表示操作哪一个信号量
short sem_op; //操作数 1 -1
short sem_flg; //操作标记
};
//semctl 销毁/控制信号量集
int semctl(int semid,int semnum,int cmd);
int semctl(int semid,int semnum,int cmd,union semun arg);
/*
IPC_STAT- 获取信号量集合的属性,通过arg.buf输出
IPC_SET - 设置信号量集合的属性,通过arg.buf输入
sem_perm.uid
sem_perm.gid
sem_perm.mode
IPC_RMID- 立即删除信号量集合
此时所有阻塞在对该信号量集合的semop函数调用,都会立即返回失败,errno设置为EIDRM
GETALL - 获取信号量集合中每个信号量的计数值,通过arg.array输出
SETALL - 设置信号量集合中每个信号量的计数值,通过arg.array输入
GETVAL - 获取信号量集合中,下标为semnum信号量的计数值,通过返回值输出
SETVAL - 设置信号量集合中,下标为semnum信号量的计数值,通过arg.val输入
注意:只有针对信号量集合中具体某个信号量操作时,才会使用semnum参数,针对整个信号量集合操作,会忽略semnum
成功因cmd而异,失败返回-1
*/
union emun{
int val; //value for SETVAL
struct sem_ds *buf; //Buffer for IPC_STAT IPC_SET
unsigned short *array; //Array for GETALL SETALL
struct seminfo *__buf; //buffer for IPC_INFO
};
struct sem_ds{
struct ipc_perm sem_perm; //权限
time_t sem_otime; //最后semop操作的时间
time_t sem_ctime; //最后修改时间
unsigned short sem_nsems; //信号量集合中信号量的数据
};
struct ipc_perm{
key_t __key; //键值
uid_t uid; //有效属主ID
gid_t gid; //有效属组ID
uid_t cuid; //有效创建者ID
gid_t cgid; //有效创建组ID
unsigned short mode; //权限
unsigned short __seq;//序列号
};
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(
我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts
在尝试实现应用auto_orient的过程之后!对于我的图片,我收到此错误:ArgumentError(noimagesinthisimagelist):app/uploaders/image_uploader.rb:36:in`fix_exif_rotation'app/controllers/posts_controller.rb:12:in`create'Carrierwave在没有进程的情况下工作正常,但在添加进程后尝试上传图像时抛出错误。流程如下:process:fix_exif_rotationdeffix_exif_rotationmanipulate!do|image|