一、信号
信号一般由某些错误条件生成,如内存段、浮点处理器错误或非法指令等。它们由shell或终端处理器生成来引起中断。它们还可以作为在进程间传递消息或修改行为的一种方式,明确地由一个进程发送给另外一个进程。信号可以被生成,捕获,响应,或忽略。
系统对信号的处理方法按情况而定,有些收到后会立即终止进程,有些则是忽略。
发送信号
int kill(pid_t pid,int sig);
int alarm(unsigned int seconds);//数秒后发送SIGALRM信号
挂起执行中的程序直到有一个信号出现为止
int pause(void);
信号编程接口,设置与sig关联的动作
int sigaction(int sig,const struct sigaction *act,struct sigaction *oact);
sigaction的成员void (*) (int) sa_handler
sigset_t sa_mask,
int sa_flags
sig,要捕获的信号
sa_handler,要转到的处理函数指针,或者为SIG_IGN,SIG——DFL,它们分别表示对信号的处理方式为忽略和默认。
sa_mask,指定一个信号集防止处理信号在处理函数未运行前发生。
sa_flags,默认情况下,希望信号处理函数被响应多次。如果只打算响应一次,然后恢复为默认行为,就置此处为SA_RESETHAND.
例子:struct sigaction act;
act.sa_handler=ouch;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGINT,&act,0);
oact,以前sigaction的副本
操作和处理sa_mask的函数
int sigaddset(sigset_t *set,int signo);
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigdelset(sigset_t *set,int signo);
判断一个给定的信号是否是一个信号集成员
int sigismember(sigset_t *set,int signo);
操作信号集函数
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
查看阻塞的信号
int sigpending(sigset_t *set);
挂起自己的执行,直到一个信号到达
int sigsuspend(const sigset_t *sigmask);
使用信号,创建通知事件,通过它引起响应,但传送的信息只限于一个信号值。
二、管道
当从一个进程连接数据流到另一个进程时,使用管道。
FILE *popen(const char *command,const char *open_mode);
int pclose(FILE *stream_to_close);
command是在shell中执行的,即完成popen要启动两个进程
int pipe(int file_descriptor[2]);
例程:int file_pipes[2];
pipe(file_pipes);
write(file_pipes[1],some_data,strlen(some_data));
read(file_pipes[0],buffer,BUFSIZ);
将管道用作标准输入和输出的方法
标准输入:
int file_pipes[2];
close(0);
dup(file_pipes[0]);
close(file_pipes[0]);
close(file_pipes[1]);
无名管道,只能在相关的程序之间传递数据,即程序是由一个共同的祖先进程启动。如果想在不相关的进程之间交换数据,就要用到命名管道
int mkfifo(const char *filename,mode_t mode);
例程:define FIFO_NAME “/tmp/my_fifo”
int pipe_fd;
mkfifo(FIFO_NAME,0777);
pipe_fd=open(FIFO_NAME,O_WRONLY);
write(pipe_fd,buffer,BUFFER_SIZE);
close(pipe_fd);
pipe_fd=open(FIFO_NAME,O_RDONLY);
read(pipe_fd,buffer,BUFFER_SIZE);
close(pipe_fd);
三、信号量
控制一些临界代码的访问,详细见《信号量学习笔记》
四、共享内存
原理:把不同进程之间的共享内存安排为同一段物理内存
我们一般使用共享内存提供对大块内存区域的有效访问,同时通过传递小消息来同步对该内存的访问
创建共享内存:
int shmget(key_t key,size_t size,int shmflg);
返回一个共享内存标识符
将创建好的内存连接到进程的地址空间
void *shmat(int shm_id,const void *shm_addr,int shmflg);
shm_id,由shmget函数返回
shm_addr,指定共享内存连接到当前进程中的地址位置。如果为空指针,表示让系统来选择共享内存出现的地址。
shmflg,一组位标志,SHM_RDONLY,只读。SHM_RND,控制共享内存地址
返回值:指向共享内存第一个字节的指针
将共享内存从当前进程中分离
int shmdt(const void *shm_addr);
控制函数
int shmctl(int shm_id,int command,struct shmid_ds *buf);
struct shmid_ds{
uid_t shm_perm.uid;
uid_t shm_perm.gid;
mode_t shm_perm.mod;
}
command 包括:
IPC_STAT 将shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET 将共享内存的值设置为shmid_ds结构中给出的值。与IPC_STAT相反。
IPC_RMID 删除共享内存段
例程:define TEXT_SZ 2048
struct shared_use_st{
int written_by_you;
char some_text[TEXT_SZ];
};
int shmid;
void *shared_memory=(void *)0;
shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666 | IPC_CREAT);
shared_memory=shmat(shmid,(void *)0,0);
shared_stuff=(struct shared_use_st *)shared_memory;
fgets(buffer,BUFSIZ,stdin);
strncpy(shared_stuff->some_text,buffer,TEXT_SZ);
shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666 | IPC_CREAT);
shared_memory=shmat(shmid,(void *)0,0);
shared_stuff=(struct shared_use_st *)shared_memory;
printf(“You wrote :%s”,shared_stuff->some_text);
shmdt(shared_memory);
shmctl(shmid,IPC_RMID,0);
五、消息队列
消息队列没有解决我们在使用命名管道满时的阻塞问题。它提供了一种在两个不相关的进程之间传递数据的相当简单而有效的办法。独立于发送和接收进程存在。
创建消息队列
int msgget(key_t key,int msgflg);
msgflg,和以前一样,由9个权限标志组成。IPC_CREAT定义的一个特殊位必须和权限标志位按位与才能创建一个新的消息队列。
返回一个队列标志符。
将消息添加到消息队列中
int msgsnd(int msgid,const void *msg_ptr,size_t msg_sz,int msgflg)
msg_ptr,是一个指向准备发送消息的指针,它必须以一个长整形成员变量开始
msg_sz,消息长度
msgflg,队列满或到达系统范围的限制时要发生的事情。IPC_NOWAIT,立即返回。
接收消息
int msgrcv(int msgid,void *msg_ptr,size_t msg_sz,long int msgtype,int msgflg);
msg_ptr,与上面介绍的一样
msgtype,取值>0,获得具有相同类型的第一个消息。类型定义在msg_ptr中。
=0,按照消息发送的顺序来接收它们。
<0,如-n,则接收消息类型等于小于n的消息。
msgflg,队列中没有相应类型的消息可以接收时将发生的事情。IPC_NOWAIT。
返回值,放回到缓存区的字节数。
控制函数
int msgctl(int smgid,int command,struct msgid_ds *buf);
struct msgid_ds{
uid_t msg_perm.uid;
uid_t msg_perm.gid;
mode_t msg_perm.mode;
}
command的值:IPC_STAT,IPC_SET,IPC_RMID
例程:
struct my_msg_st{
long int my_msg_type;
char some_text[BUFSIZ];
};
int msgid;
long int msg_to_receive=0;
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
struct my_msg_st some_data;
fgets(buffer,BUFSIZ,stdin);
somedata.my_msg_type=1;
strcpy(some_data.some_text,buffer);
msgsnd(msgid,(void *)&some_data,MAX_TEXT,0);
msgid=msgget((key_t)1234,0666 | IPC_CREAT);
struct my_msg_st some_data;
msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0);
printf(“You wrote:%s”,some_data.some_text);
六、套接字
上面的几种通信办法只能运行在同一台机器上。套接字实现了计算机网络中的通信。
总结:信号,一种中断处理机制,可以由此引起一些其它的函数调用。
信号量,处理临界区代码
共享内存,管道,消息队列,都可以用于大量数据的通信。根据其特点,酌情选择使用。
套接字,主要用于网络编程中。