同步异步的概念与消息的通知机制有关,阻塞非阻塞的概念与等待消息通知时的状态有关。
同步异步是针对应用程序和内核的交互而言的。举个例子:当进程触发IO操作后,
同步:进程需要自己来确定什么时候IO操作完成,进程自己需要不断的查询来确定任务是否完成。(期间进程可以去做其他事)
异步:进程不需要自己确定什么时候IO操作完成,当任务完成后,内核会通知该进程。
阻塞:进程停止在当前操作,不进行后面的操作;直到当前操作完成。(阻塞是指当前操作的运行模式)
非阻塞:进程不停止在当前操作,当前操作会立即返回一个结果,然后进行后面的操作。(非阻塞是指当前操作的运行模式)
同步阻塞:进程停止在当前操作,期间进程不断查询当前操作是否完成。
同步非阻塞:进程不停止在当前操作A,执行后面的其他操作B...,但期间不断的查询操作A是否完成。
异步阻塞:进程停止在当前操作A,并不执行后面的操作,等操作A完成后,内核通知进程,进程再执行后面的操作。
异步非阻塞:进程不停止在当前操作A,转而去执行后面的操作,操作A完成后,内核通知进程操作A执行完成。
对于非阻塞而言:如果操作A还没完成,但是当前进程已经执行完成,进程会停下来等待操作A完成吗?在等待的这段时间进程又是什么状态呢?
对于非阻塞而言,操作A会立即返回结果。
下面用网络中的recvfrom来具体介绍阻塞与非阻塞的区别。
对于network IO而言,它涉及到两个对象,内核和调用IO的进程,一般划分为两个阶段:
1、等待数据准备(Waiting for the data to be ready)
2、将数据从内核拷贝到进程(Copying the data from the kernel to the process)
阻塞IO模式:
非阻塞模式:
异步模式:
用一个udp客户端服务端的程序来解释一下同步阻塞与同步非阻塞的区别:(其客户端是一样的,主要区别是服务端)
客户端:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(50001);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
char sendline[100];
sprintf(sendline, "Hello, world!");
sendto(sockfd, sendline, strlen(sendline), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
close(sockfd);
return 1;
}
服务端阻塞:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(50001);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
int n;
char recvline[1024];
recvfrom(sockfd, recvline, 1024, 0, NULL, NULL);
printf("%s\n", recvline);
close(sockfd);
}
服务端非阻塞:
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
sockfd = socket(PF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(50001);
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
int n;
char recvline[1024];
int result = recvfrom(sockfd, recvline, 1024, MSG_DONTWAIT, NULL, NULL);
while(result != -1){
result = recvfrom(sockfd, recvline, 1024, MSG_DONTWAIT, NULL, NULL);
printf("continue recvfrom");
}
printf("%s\n", recvline);
close(sockfd);
}
在阻塞模式中,服务端会一直等待数据,不会执行下面的操作。
在非阻塞模式中,服务端会立即返回结果,在此例子中,没有接受到的数据,就返回-1,因此在非阻塞模式中会一直服务端会一直输出“continue recvfrom”,直到有数据过来,循环停止。