计算机系统-几种并发编程

计算机系统-几种并发编程,第1张

第12章 并发编程

什么是并发:如果逻辑控制流在时间上重叠,那么他就是并发的。



并发主要被看作是一种 *** 作系统内核用来运行多个应用程序的机制。


但是并发不仅仅限于内核。



应用级并发的几种应用:

  • 访问慢速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多路复用的并发编程

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));
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/562508.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-01
下一篇 2022-04-01

发表评论

登录后才能评论

评论列表(0条)

保存