• Each process has its own address space. Therefore, individual processes cannot communicate, unlike threads.
• Inter process communication: Linux/Unix provides several ways to allow communication
signal
pipes
FIFO queues
shared memory
semaphores
sockets
• Unix/Linux allows us to handle exceptions that arise during execution (e.g., interrupt, floating point error, segmentation fault etc.).
• A process recieves a signal when such a condition occurs.
void (∗signal( int sig,void(∗handler)(int )))( int )
• determines how subsequent signals will be handled.
• pre-defined behavior: SIG_DFL (default), SIG_IGN (ignore)
• returns the previous handler.
这里的exceptions应该就是运行时异常吧,从signal的类型可以得到运行时异常的类别,这个在实际应用中和工作面试中都会经常用到哦:)
SIGABRT abnormal termination
SIGFPE floating point error
SIGILL illegal instruction
SIGINT interrupt
SIGSEGV segmentation fault
SIGTERM termination request
SIGBUS bus error
SIGQUIT quit
The two signals SIGSTOP, SIGKILL cannot be handled.
int raise( int sig) can be used to send signal sig to the program.
Notes:
• There can be race conditions.
• signal handler itself can be interrupted.
• use of non-reentrant functions unsafe.
• sigproc mask can be used to prevent interruptions.
• handler is reset each time it iscalled.
signal实际上存在共享数据:操作系统中的signal记录,因此线程同步的问题也存在于signal中。
#include <stdio.h>
void sigproc()
{
printf("you have pressed ctrl−c \n");
}
void quitproc()
{
printf("ctrl−\\ pressed toquit");
exit(0); ∗normal exit status∗/
}
main ( )
{
signal(SIGINT, sigproc);
signal(SIGQUIT, quitproc);
printf(‘‘ctrl−c disabled use ctrl−\\ to quit\n’’);
for( ; ; ); /∗infinite loop∗/
}
signal方法的作用是定义接受到某种信号时对应的操作。
pid_t fork (void)
• fork() is a system call to createa new process
• In the child process, it returns 0
• In the parent process, it returns the PID (process id) of the child.
• The child PID can be used to send signals to the child process.
• returns -1 on failure (invalid PID)
原来创建一个子进程是如此简单,只需复制自己即可。操作系统自身应该是所有进程的祖先进程。
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
int main(){
pid_t pid =fork();
int i;
if(pid){
for(i=0; i<5; i++){
sleep(2);
printf("child process: %d\n", i);
}
}
printf("parent process: %d\n", i);
}
运行结果:
childprocess: 0
parent process: 0
child process: 1
child process: 2
parent process: 1
child process: 3
child process: 4
parent process: 2
parent process: 3
parent process: 4
• fork() makes a full copy of the parents address space.
• pid_t getpid() returns PID of the current process.
• pid_t getppid() returns PID of the parent process.
• wait(int∗) is used to wait for the child to finish.
• waitpid() is used to wait for a specific child.
Zombies:
• the child process can exit before the parent
• stray process is marked as <defunct>
• preap can be used to reap zombie processes.
子进程可以在父进程结束之前结束,父进程能否在子进程之前结束呢?我很怀疑,因为子进程有父进程的PID,如果父进程没了,那么这个PID就为空,看起来不怎么舒服。
Pipes are used in unix to redirect output of one command to another. Pipes also allow parent processes to communicate with its children.
Examples
• ls | more - displays results of ls one screen at a time
• cat file.txt | sort - displays contents of file.txt in sorted order
int pipe(int FILEDES[2])
• A pipe can be thought of as a pair of file descriptors
• no physical file is associated with the file descriptor
• one end is opened in write mode.
• other end is opened in read mode.
管道在UNIX中是一个十分重要的工具,实现简单但功能强大,很符合UNIX的style。其实现可以看作用一根两端为fd(file descriptor)的管道将两个进程连接起来,管道前面的进程会有输出到一个文件,而后面的进程则会读取一个文件。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int main(void)
{
int pfds[2];
char buf[30];
if (pipe(pfds) == -1) {
perror("pipe");
exit(1);
}
printf("writing to file descriptor #%d\n", pfds[1]);
write(pfds[1], "test", 5);
printf("reading from filedescriptor #%d\n", pfds[0]);
read(pfds[0], buf, 5);
printf("read \"%s\"\n",buf);
return 0;
}
• FIFO queues may be thought of as named pipes.
• Multiple processes can read and write from a FIFO.
• Unlike pipes, the processes can be unrelated.
• FIFOs can be created using mknod system call.
int mknod(const char ∗path, mode_t mode, dev_t dev)
• <sys/stat.h> contains the declaration for mknod.
• mknod used to create special files - devices, fifos etc.
• mode can have special bits such as S_IFIFO | 0644
• dev is interpreted based on the mode.
Example: mknod("myfifo", S_IFIFO | 0644 , 0);
FIFO和管道本质上都是使用读写同一个文件的方法实现线程间的通信。