什么是并发:如果逻辑控制流在时间上重叠,那么他就是并发的。
并发主要被看作是一种 *** 作系统内核用来运行多个应用程序的机制。
但是并发不仅仅限于内核。
应用级并发的几种应用:
- 访问慢速IO设备
- 与人交互
- 通过推迟工作以降低延时
- 服务多个网络客户端
- 在多核机器上进行并行计算
现代 *** 作系统提供了三种基本的构造并发程序的方法: - 进程
- I/O多路复用
- 线程
- 基于进程的并发服务器
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <sys/socket.h>
6 #include <unistd.h>
7 //#include
8 #include<netinet/in.h>
9 #include <iostream>
10 #include <signal.h>
11 #include <memory>
12 #include <string>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <memory>
16 #include <cstring>
17 using m_sockaddr_in = struct sockaddr_in;
18 typedef struct sockaddr_in m_sockaddr_in;
19 void sigchld_handler(int sig)
20 {
21 while(waitpid(-1,0,WNOHANG) > 0)
22 ;
23 return;
24 }
25 int open_listenfd( const sockaddr_in& id,const int port)
26 {
27 int socket_id = socket(AF_INET,SOCK_STREAM,0);
28 //id_len = sizeof(id);
29 sockaddr_in server_sock;
30 memset(&server_sock,0,sizeof(server_sock));
31 server_sock.sin_family = AF_INET;
32 server_sock.sin_addr.s_addr = inet_addr("127.0.0.1");
33 server_sock.sin_port = htons(1234);
34 bind(socket_id,(sockaddr*)&server_sock,sizeof(server_sock));
35 listen(socket_id,20);
36 //socklen_t id_size = sizeof(id);
37 //int client_sock = accept(socket_id,(sockaddr*)&id,&id_size);
38 return socket_id;
39 }
40 void echo(int connfd)
41 {
42 std::string str = "hello";
43 write(connfd,str.c_str(),sizeof(str));
44 }
45 int main(int argc,char ** argv)
46 {
47 int listenfd,connfd,port;
48 socklen_t clientlen = sizeof(m_sockaddr_in);
49 sockaddr_in clientaddr;
50 if(argc!=2){
51 fprintf(stderr,"usage:%s \n" ,argv[0]);
52 exit(0);
53 }
54 port = atoi(argv[1]);
55 signal(SIGCHLD,sigchld_handler);
56 listenfd = open_listenfd(clientaddr,port);
57 while(1)
58 {
59 connfd = accept(listenfd,(sockaddr*)&clientaddr,&clientlen);
60 if(fork() == 0)
61 {
62 close(listenfd);
63 echo(connfd);
64 close(connfd);
65 exit(0);
66 }
67 close(connfd);
68 }
69 }
客户端
1 #include <iostream>
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <arpa/inet.h>
7 #include <sys/socket.h>
8 int main(int argc,char*argv[])
9 {
10 int sock_id = socket(AF_INET,SOCK_STREAM,0);
11 sockaddr_in clientAddr;
12 memset(&clientAddr,0,sizeof(clientAddr));
13 clientAddr.sin_family = AF_INET;
14 clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
15 clientAddr.sin_port = htons(1234);
16 connect(sock_id,(sockaddr*)&clientAddr,sizeof(clientAddr));
17 char buf[20] = {0};
18 read(sock_id,buf,sizeof(buf) - 1);
19 puts("message");
20 puts(buf);
21 return 0;
22 }
进程的优劣:共享文件表,不共享用户地址空间。
必须显示进行IPC通信。
IO多路复用的基本思路是使用select(epoll)函数,要求内核挂起进程,只有在一个或者多个IO事件发生后,才将控制返回给应用程序。
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using m_sockaddr_in = struct sockaddr_in;
typedef struct sockaddr_in m_sockaddr_in;
void sigchld_handler(int sig)
{
while(waitpid(-1,0,WNOHANG) > 0)
;
return;
}
int open_listenfd( const sockaddr_in& id,const int port)
{
int socket_id = socket(AF_INET,SOCK_STREAM,0);
//id_len = sizeof(id);
sockaddr_in server_sock;
memset(&server_sock,0,sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = inet_addr("127.0.0.1");
server_sock.sin_port = htons(1234);
bind(socket_id,(sockaddr*)&server_sock,sizeof(server_sock));
listen(socket_id,20);
//socklen_t id_size = sizeof(id);
//int client_sock = accept(socket_id,(sockaddr*)&id,&id_size);
return socket_id;
}
void echo(int connfd)
{
std::string str = "hello";
write(connfd,str.c_str(),sizeof(str));
}
void command(){
char buf[100];
if(!fgets(buf,100,stdin))
exit(0);
printf("%s",buf);
}
int main(int argc,char ** argv)
{
int listenfd,connfd,port;
socklen_t clientlen = sizeof(m_sockaddr_in);
sockaddr_in clientaddr;
fd_set read_set,ready_set;
if(argc!=2){
fprintf(stderr,"usage:%s \n" ,argv[0]);
exit(0);
}
port = atoi(argv[1]);
sockaddr_in id;
listenfd = open_listenfd(id,port);
FD_ZERO(&read_set);
FD_SET(STDIN_FILENO,&read_set);
FD_SET(listenfd,&read_set);
while(1){
ready_set = read_set;
select(listenfd+1,&ready_set,NULL,NULL,NULL);
if(FD_ISSET(STDIN_FILENO,&ready_set))
command();
if(FD_ISSET(STDIN_FILENO,&ready_set)){
connfd = accept(listenfd,(sockaddr*)&clientaddr,&clientlen);
echo(connfd);
close(connfd);
}
}
}
/*
* #include
* #include
* int select(int n,fd_set* fdset,NULL,NULL,NULL);
* FD_ZERO(int fd,fd_set* fdset);
* FD_CLR(int fd,fd_set* fdset);
* FD_SET(int fd,fd_set* fdset);//描述符集合
* FD_ISSEN(int fd,fd_set* fdset);
* */
基于线程的并发编程
基于进程的并发编程,每个流使用了单独的进程,流共享数据很困难,第二种创建了自己的逻辑流,只有一个进程,所有流共享一个地址空间。
基于线程的,是两种方法的混合。
线程是运行在进程上下文中的逻辑流 。
每个线程都有自己的线程上下文,包括唯一的整数线程ID(thread ID,TID)。
栈、栈指针,程序计数器,通用目的的寄存器和条形码。
所有的运行在一个进程的线程共享该进程的整个虚拟空间。
每个进程开始生命周期时都是单一线程,这个线程称为主线程。
在某一时刻线程创建一个对等线程,从这个时间点开始,两个线程就并发运行。
线程的终止方式:
1当顶层的线程例程返回时,线程会隐式的终止。
2通过调用pthread_exit函数,线程会显示的终止。
如果主线程调用pthread_exit,他会等待其他对等线程终止,然后在终止主线程和整个进程,返回值为thread_return.
3某个对等线程调用unix的exit函数,该函数终止进程以及所有与该进程相关的线程。
4另外一个对等线程通过当前线程ID作为参数调用pthread_cancel函数来终止当前线程。
回收终止的线程:
- 通过调用pthread_join函数等待其他线程终止。
pthread_join是阻塞函数,而且只能等待一个指定的线程终止,不同于UNIX中wait函数。
- 分离线程,线程是可结合的或者是分离的。
一个可结合的线程能够被其他线程收回其资源和杀死。
一个分离的线程不能被其他线程回收或者杀死。
他的存储器资源在它终止时由系统自动释放。
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
void echo(int connfd);
void *thread(void *vargp);
int open_listenfd(const int port);
int main(int argc,char* argv[])
{
int listenfd,*connfdp,port;
socklen_t clientlen = sizeof(sockaddr_in);
sockaddr_in clientaddr;
pthread_t tid;
if(argc != 2)
{
fprintf(stderr,"usage:%s \n" ,argv[0]);
exit(0);
}
port = atoi(argv[1]);
listenfd = open_listenfd(port);
while(1){
connfdp =(int*) malloc(sizeof(int));
*connfdp = accept(listenfd,(sockaddr*)&clientaddr,&clientlen);
pthread_create(&tid,NULL,thread,connfdp);
}
std::cout << "Hello world" << std::endl;
return 0;
}
void *thread(void *vargp)
{
int connfd = *((int*)vargp);
pthread_detach(pthread_self());
free(vargp);
echo(connfd);
close(connfd);
return NULL;
}
int open_listenfd(const int port)
{
int socket_id = socket(AF_INET,SOCK_STREAM,0);
//id_len = sizeof(id);
sockaddr_in server_sock;
memset(&server_sock,0,sizeof(server_sock));
server_sock.sin_family = AF_INET;
server_sock.sin_addr.s_addr = inet_addr("127.0.0.1");
server_sock.sin_port = port;
bind(socket_id,(sockaddr*)&server_sock,sizeof(server_sock));
listen(socket_id,20);
//socklen_t id_size = sizeof(id);
//int client_sock = accept(socket_id,(sockaddr*)&id,&id_size);
return socket_id;
}
void echo(int connfd)
{
std::string str = "hello";
write(connfd,str.c_str(),sizeof(str));
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)