精华内容
下载资源
问答
  • c语言多线程并发服务器

    千次阅读 2019-08-15 16:38:30
    文章目录c语言多线程并发服务器服务端客户端 c语言多线程并发服务器 服务端 #include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/socket.h> #include<arpa/inet.h...

    c语言多线程并发服务器

    服务端

    #include<stdio.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<string.h>
    #include<strings.h>
    #include<ctype.h>
    #include<stdlib.h>
    #include<pthread.h>
    void *run(void *arg);
    int main(){
    		//lfd:socket返回的文件描述符,用lfd监听并接受客户端连接
       		//cfd:客户端链接上来返回的cfd,用cfd和客户端通信
            int lfd,cfd;
    		char client_ip[128];
            //serv_addr服务器地址
            //client_addr客户端地址
            struct sockaddr_in serv_addr,client_addr;
            socklen_t client_len;
            pthread_t tid;
            
            //socket创建服务器返回lfd文件描述符
            lfd = socket(AF_INET,SOCK_STREAM,0);
            bzero(&serv_addr,sizeof(serv_addr));
            //ipv4
            serv_addr.sin_family = AF_INET;
            //端口 本地字节序转网络字节序 host to net short 大小端存储问题
            serv_addr.sin_port = htons(9999);
            //ip host to net long
            serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
            //bind
            bind(lfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
            //监听是否有客户连接
            listen(lfd,128);
            printf("wait for connect...\n");
            
            while(1){
               client_len = sizeof(client_addr);//客户端地址长度
               //连接成功返回cfd,用cfd和客户通信
               cfd = accept(lfd,(struct sockaddr*)&client_addr,&client_len);
               printf("client:%s\t%d\n",
    		   inet_ntop(AF_INET,&client_addr.sin_addr.s_addr,client_ip,sizeof(client_ip)),
    		   ntohs(client_addr.sin_port));
    		   //创建线程 回调 run方法  cfd做参数传入 
               pthread_create(&tid,NULL,run,(void *)cfd);
               
    		}
    		return 0;
    } 
    void *run(void *arg){
    	int cfd = (int ) arg;
    	pthread_detach(pthread_self());
    	char buf[1024];//缓冲区
    	int len,i;
    	while(1){
    		len = read(cfd,buf,sizeof(buf));
    		printf("receive: %s\n",buf);
    		if(len<=0)break;
    		for(i=0;i<len;++i)
    		    buf[i] = toupper(buf[i]);
    		write(cfd,buf,len);
    	}
    	close(cfd);
    }
    

    客户端

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<string.h>
    #include<sys/types.h>
    #include<netinet/in.h>
    #include<sys/socket.h>
    #include<sys/wait.h> 
    #define DEST_PORT 9999//目标地址端口号 
    #define DEST_IP "127.32.255.2"/*目标地址IP,这里设为本机,不一定非得是127.0.0.1,只要127开头并且不是127.0.0.0和127.255.255.255即可*/ 
    #define MAX_DATA 100//接收到的数据最大程度 
     
    int main(){
    	int sockfd;
    	struct sockaddr_in dest_addr;
    	char buf[MAX_DATA];
     
    	sockfd=socket(AF_INET,SOCK_STREAM,0);
    	
    	dest_addr.sin_family=AF_INET;
     	dest_addr.sin_port=htons(DEST_PORT);
    	dest_addr.sin_addr.s_addr=inet_addr(DEST_IP);
    	bzero(&(dest_addr.sin_zero),8);
    	connect(sockfd,(struct sockaddr*)&dest_addr,sizeof(struct sockaddr));
    
    	printf("connect success");
    	while(1){
    		char send_buf[512] = "";
    		scanf("%s",&send_buf);
    		write(sockfd,send_buf,sizeof(send_buf));
    		
    		read(sockfd,send_buf,sizeof(send_buf));
        	printf("client receive:%s\n",send_buf);
    	}
    
    	return 0;
    } 
    
    

    centos执行
    gcc -o server.out server.c -lpthread
    gcc -o client.out client.c -lpthread
    得到执行文件server.out,client.out
    用xshell 对一个虚拟机开两个item窗口,一个执行./server.out ,另一个执行./client.out,可以开多个客户端通信

    展开全文
  • 但是,我们实际上也可以编写一个进程里同时运行线程的程序,线程是由内核调度的,从进程间通信角度来看,一个给定进程内的所有线程共享同样的全局变量。每个线程具有独立的线程上下文,包括一个唯一的整数线程ID...

    线程介绍

    线程就是运行在一个进程上下文中的逻辑流,一般来说,程序是由每个进程中的单一线程来组成的。但是,我们实际上也可以编写一个进程里同时运行多个线程的程序,线程是由内核调度的,从进程间通信角度来看,一个给定进程内的所有线程共享同样的全局变量。每个线程具有独立的线程上下文,包括一个唯一的整数线程ID,栈,栈指针,程序计数器,通用目的寄存器和条件码。所有运行在一个进程中的线程共享该进程的整个虚拟地址空间。基于线程的逻辑流结合了基于进程和基于IO多路复用的流的特性,同进程一样,线程有内核自动调度,并且内核通过一个整数ID来识别线程,同基于多路IO复用一样,多个线程运行在单一进程的上下文之中,因此共享整个进程的虚拟地址空间,包括代码、数据、堆和共享库以及打开的文件。

    线程的生命周期

    每个进程一开始都是由单一主线程构成的,在某一时刻,主线程创建一个对等线程,从这个时间点开始,两个线程就开始并发地运行。最后,因为主线程执行一个慢速系统调用,例如read函数或者sleep函数,线程就会被内核挂起,控制就会通过上下文切换传递到对等线程。对等线程就这样交替执行,以此类推。

    并发服务器代码实现

    //本程序是基于多线程的并发服务器

    //为了避免赋值语句在accept之后才完成的,那么对等线程中的局部变量connfd就得到下一次连接的描述符值,不幸的是,两个线程在同一个描述符上执行输入和输出

    //为了避免这种致命竞争,必须将每个accept返回的已连接符分配到它自己的动态分配的存储器块

    #include "csapp.h"

    void echo(int connfd)

    {

    int n;

    char buf[MAXLINE];

    rio_t rio;

    rio_readinitb(&rio,connfd);

    //带缓冲的读取函数

    while((n=rio_readlineb(&rio,buf,MAXLINE))>0) {

    //向连接符写入内容

    printf("server received %d bytes \n",n);

    rio_writen(connfd,buf,n);

    }

    }

    void *thread(void *vargp); //线程函数声明

    //主函数入口

    int main(int argc,char **argv)

    {

    int listenfd,*connfd,port; //监听描述符,连接符,端口号

    socklen_t clientlen=sizeof(struct sockaddr_in); //客户端地址长度

    struct sockaddr_in clientaddr; //新建客户端地址

    pthread_t tid; //线程id

    if(argc!=2) {

    fprintf(stderr,"usage :%s \n",argv[0]); //提示执行格式

    exit(0); //正常退出主程序,主进程

    }

    port=atoi(argv[1]); //把端口号转成整型

    listenfd=open_listenfd(port); //打开监听端口号

    while(1) { //无限循环,等待接受请求

    connfd=malloc(sizeof(int)); //动态分配内存给连接描述符,这是为了避免两个线程在同一个描述符上输入输出,导致两个线程在同一个描述符上的不正当竞争

    *connfd=accept(listenfd,(SA *)&clientaddr,&clientlen); //接受请求,已连接描述符

    pthread_create(&tid,NULL,thread,connfd); //新建线程,并且传递参数connfdp进入线程

    }

    }

    void *thread(void *vargp)

    {

    int connfd=*((int *)vargp);//接受参数

    pthread_detach(pthread_self()); //分离线程,使得它不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放

    free(vargp); //释放参数存储空间

    echo(connfd); //回应客户端

    close(connfd); //关闭已连接描述符,这里不用在主线程中关闭,因为线程共享同一虚拟地址空间,此处关闭即可

    return NULL;//线程结束

    }

    上面的多线程编译时,要加上-pthread参数,程序运行如下:

    zzw@zzw-ThinkPad-Edge-E430c:~$ telnet localhost 9999

    Trying 127.0.0.1...

    Connected to localhost.

    Escape character is '^]'.

    hello

    hello

    zzw@zzw-ThinkPad-Edge-E430c:~/doc_main/CProgram/Concurrency$ ./echoservert.o 9999

    server received 7 bytes

    展开全文
  • #include &lt;sys/types.h&gt; #include &lt;sys/socket.h&gt; #include &lt;netinet/in.h&gt; #include &lt;arpa/inet.h&gt; #include &lt;stdio.h&...#inc.
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>
    #include <errno.h>
    #include <pthread.h>
    
    typedef struct SockInfo{
    	int fd;
    	struct sockaddr_in addr;
    	pthread_t id;
    }SockInfo;
    
    void* worker(void* arg)
    {
    	SockInfo* info = (SockInfo*)arg;
    	char buf[1024];
    	char ip[64];
    	while(1){
    		printf("Client IP: %s, port: %d\n",
    			inet_ntop(AF_INET, &info->addr.sin_addr.s_addr, 
    				ip,sizeof(ip)),
    			ntohs(info->addr.sin_port));
    
    		int len = read(info->fd, buf, sizeof(buf));
    		if(len == -1){
    			perror("read error");
    			pthread_exit(NULL);
    		}
    		else if(len == 0){
    			printf("client unconnect\n");
    			close(info->fd);
    			break;
    		}
    		else{
    			printf("recv buf: %s\n", buf);
    			write(info->fd, buf, len);
    		}
    		 
    
    
    	}
    	return NULL;
    }
    			
    
    int main(int argc, char* argv[])
    {
    
    	if(argc <2){
    		printf("eg: ./a.out port\n");
    		exit(1);
    	}
    
    	int port = atoi(argv[1]);    // port
    
    
    	int Socket_fd = socket(AF_INET, SOCK_STREAM, 0);   // create socket
    
    	if(Socket_fd==-1){
    		perror("create socket error");
    		exit(EXIT_FAILURE);
    	}
    
    	struct sockaddr_in serv;
    
    	memset(&serv, 0 ,sizeof(serv));
    
    	serv.sin_family = AF_INET;                               // ipv4
    	serv.sin_port = htons(port);                             // port
            serv.sin_addr.s_addr = INADDR_ANY;                        // ip
    
    	if(-1==bind(Socket_fd, (struct sockaddr*)&serv, sizeof(serv))){
    		perror("bind error");
    		close(Socket_fd);
    		exit(EXIT_FAILURE);
    	}
    
    	if(-1==listen(Socket_fd,36)){
    		perror("listen error");
    		close(Socket_fd);
    		exit(EXIT_FAILURE);
    	}
    	printf("Start accept ......\n");
    
    	int i=0;
    	SockInfo info[32];
    	for(i=0;i<sizeof(info)/sizeof(int);i++)
    		info[i].fd=-1;
            socklen_t cli_len = sizeof(struct sockaddr_in);
    	while(1){
    
    		for(i=0;i<32;i++){
    			if(info[i].fd == -1)
    				break;
    		}
    
    		if(i==32)
    			break;
    
    		// parent pthread
    		info[i].fd = accept(Socket_fd,
    				(struct sockaddr*)&info[i].addr, &cli_len);
    
    		// child pthread
    		pthread_create(&info[i].id, NULL, worker, &info[i]);
    
    		//
    		pthread_detach(info[i].id);
    	
    	}
    	
    	close(Socket_fd);
    	// only quit child pthread
    	pthread_exit(NULL);
    	return 0;
     	
    }
    
    

     

    展开全文
  • 但是近期我发现了一个相当好用的库,这个库只需要增加一个修饰符就可以使原生的python多线程实现真正意义上的并发。本文将和大家一起回顾下GIL对于多线程的影响,以及了解通过一个修饰符就可以实现和C++一样的多线程...

    Python 多线程因为GIL的存在,导致其速度比单线程还要慢。但是近期我发现了一个相当好用的库,这个库只需要增加一个修饰符就可以使原生的python多线程实现真正意义上的并发。本文将和大家一起回顾下GIL对于多线程的影响,以及了解通过一个修饰符就可以实现和C++一样的多线程。

    GIL的定义

    GIL的全称是global interpreter lock,官方的定义如下:

    In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)

    从官方的解释来看,这个全局锁是用来防止多线程同时执行底层计算代码的。之所以这么做,是因为底层库Cpython,在内存管理这块是线程不安全的。

    GIL有好处吗

    对GIL的第一印象是这东西限制了多线程并发,对python而言是个弊大于利的存在。但是从stackoverflow上的讨论来看,这个存在还是相当有必要的。

    • 增加了单线程的运行速度
    • 可以更方便地整合一些线程不安全的C语言库到python里面去
      首先单线程的运行速度更快了,因为有这个全局锁的存在,在执行单线程计算的时候不需要再额外增加锁,减少了不必要的开支。第二个则是可以更好地整合用C语言所写的python库。现在其实挺多用C语言写好底层计算然后封装提供python接口的,比如数据处理领域的pandas库,人工智能领域的计算框架Tensorflow或者pytorch,他们的底层计算都是用C语言写的。由于这个全局锁的存在,我们可以更方便(安全)地把这些C语言的计算库整合成一个python包,对外提供python接口。

    GIL对性能的影响大吗

    对于需要做大量计算的任务而言,影响是相当大的。我们先来看一段单线程代码:

    class A(object):
        def run(self):
            ans = 0
            for i in range(100000000):
                ans += i
    a = A()
    for _ in range(5):
      a.run()
    

    以上这段代码是跑5次计算,每次计算是从1累加到1千万,跑这段代码需要17.46s。
    紧接着,我们用python的多线程库来实现一个多线程计算:

    import threading
    
    class A(object):
        def run(self):
            ans = 0
            for i in range(100000000):
                ans += i
    threads = []
    for _ in range(5):
        a = A()
        th = threading.Thread(target=a.run)
        th.start()
        threads.append(th)
    for th in threads:
        th.join()
    

    这里我们启动了5个线程同时计算,然后我们又测试下时间: 41.35秒!!!这个时候GIL的问题就体现出来了,我们通过多线程来实现并发,结果比单线程慢了2倍多。

    一个神奇的修饰符

    话不多说,我们先来看下代码。以下这段代码和上面的多线程代码几乎一样。但是我们要注意到,在类A的定义上面,我们增加了一个修饰符*@parl.remote_class*。

    import threading
    import parl
    
    @parl.remote_class
    class A(object):
        def run(self):
            ans = 0
            for i in range(100000000):
                ans += i
    threads = []
    parl.connect("localhost:6006")
    for _ in range(5):
        a = A()
        th = threading.Thread(target=a.run)
        th.start()
        threads.append(th)
    for th in threads:
        th.join()
    

    现在我们来看下计算时间:3.74秒!!!相比于单线程的17.46s,这里只用了接近1/5的时间(因为我们开了5个线程)。这里是我觉得比较神奇的地方,并没有做太多的改动,只是在我的单线程类上面增加了一个修饰符,然后用原生的python多线程继续跑代码就变得相当快了。

    完整的使用说明:

    1. 安装这个库:
    pip install --upgrade git+https://github.com/PaddlePaddle/PARL.git
    
    1. 在本地通过命令启动一个并发服务(只需要启动一次)
    xparl start --port 6006
    
    1. 写代码的时候通过修饰符修饰你要并发的类@parl.remote。
      这里需要注意的是只有经过这个修饰符修饰的类才可以实现并发。
    2. 在代码最开始的时候通过parl.connect(‘localhost:6006’)来初始化这个包。

    最后贴下这个库的使用文档:
    https://parl.readthedocs.io/en/latest/parallel_training/setup.html
    源码在这里:
    https://github.com/PaddlePaddle/PARL/tree/develop/parl/remote

    后续会继续研究源码,看下是怎么做到一个修饰符就能加速的。大家如果读过了源码可以一起讨论下:)

    展开全文
  • 但是近期我发现了一个相当好用的库,这个库只需要增加一个修饰符就可以使原生的python多线程实现真正意义上的并发。本文将和大家一起回顾下GIL对于多线程的影响,以及了解通过一个修饰符就可以实现和C++一样的多线程...
  • 一、volatile的作用关键字volatile是使变量在线程间可见,也就是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。通过使用volatile关键字,强制的从公共内存中读取变量的值,内存结构如图...
  • 因为更喜欢钻研技术, 管理上欠缺的太. 呵呵, 废话太了. 切入正题. 最近需要计划做一个服务器的程序. 和我们用VC++开发的客户端程序做对接, 我在LINUX服务器下用C写了一段简单的服务器, 代码...
  • 实现多线程的两种方法及源码分析线程的生命周期及相关方法synchronized关键字volatile关键字Java内存模型一、实现多线程的两种方法及源码分析官方文档说明,实现多线程的方法有且仅有两种,其他实现方式底层说白了...
  • C语言多线程操作

    千次阅读 2019-11-27 22:39:38
    C语言多线程操作 目录 C语言多线程 创建线程 终止线程 注意 信号量机制 参考博文: 返回目录 C语言多线程 多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序。一般...
  • 但是,我们实际上也可以编写一个进程里同时运行线程的程序,线程是由内核调度的,从进程间通信角度来看,一个给定进程内的所有线程共享同样的全局变量。每个线程具有独立的线程上下文,包括一个唯...
  • 前言多线程并发问题,基本是面试必问的。今年刚刚毕业准备找实习的同学或者经历过最近一段时间面试的朋友们,相应你们应该都有一个相同的问题被问到,那就是多线程与高并发因为最近和腾讯、阿里包括字节和京东等一线...
  • 1.将一个串行执行的多线程改成并发执行,不知道自己这样改对不对,如有错误请多多指教,谢谢各位大佬。 2.附上两个代码(串行执行和并发执行): ``` #include #include #include #include int ...
  • 文章目录一....结构体与多线程五.多线程的同步与互斥 一.线程与进程 二.并发与并行 三.C语言中的线程 我们先来看一下线程最基础的三个方法: 3.1创建线程 pthread_create pthread_create(pthread...
  • C语言中的多线程简介

    2019-08-17 21:21:40
    多线程就是多个线程同时并发执行。 (注意并发与并行的区别,并行同时执行不同的任务,并行是交替执行不同的任务。) 1,为什么要用多线程? 1)避免阻塞 单个线程中的程序,是按照顺序执行的,排在前面的程序...
  • c语言写的多协议多服务并发的服务器,主要用到多线程socket编程
  • 尹成老师带你步入 C 语言的殿堂,讲课生动风趣、深入浅出,全套视频内容充实,整个教程以 C 语言为核心,完整精彩的演练了数据结构、算法、设计模式、数据库、大数据高并发检索、文件重定向、多线程同步、进程通讯、...
  • 进程是一个具有独立功能的程序关于某个数据集合的一次而可以并发执行的运行活动,是处于活动状态的计算机程序...再操作系统设计上,从进程演化出线程,最主要的目的就是更好的支持处理器系统和减小上下文件切换开销。
  • 一、多线程与内存池的结合使用: 一个线程memorymalloc,另一个线程memoryfree,效率是malloc\free的1.3倍(单线程时是3倍,本来双线程应该是6倍,但因为使用了线程的同步,使线程地并发变为了串行,故效率也应是3倍...
  • C语言笔记13--多线程

    2018-09-11 00:02:40
    多线程并发执行的,可以提高程序的运算速度,但也不是无限的提高。多线程在处理大量数据中会体现出非常大的优越性,所以今天来谈谈C中的多线程。 1.多线程的简单用法: 同时创建多个窗口 #include&lt;stdio...
  • 1.多线程简介线程(Thread)也称轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位。线程自身不拥有资源,只拥有一些在运行中必不可少的资源,但他可与同属一个进程的...
  • C语言多线程基础-02-临界区,互斥量

    千次阅读 2017-11-01 19:29:43
    多线程并发访问冲突多线程并发访问冲突问题示例:#include #include #include<Windows.h>//定义宏threadnumber用来设置创建线程的个数 #define threadnumber 50 //定义一个全局变量 int number; DWORD WINAPI ...
  • 尹成老师带你步入 C 语言的殿堂,讲课生动风趣、深入浅出,全套视频内容充实,整个教程以 C 语言为核心,完整精彩的演练了数据结构、算法、设计模式、数据库、大数据高并发检索、文件重定向、多线程同步、进程通讯、...
  • 多线程并发之Volatile关键字 Volatile关键字 这里先介绍一下Volatile的意思,话不多说,上翻译 Volatile     [ˈvɒlətaɪl]     adj. 易变的;无定性的;无常性的;可能急剧波动的;不稳定...
  • Linux多线程设计是指基于Linux操作系统下的多线程设计,包括多任务程序的设计,并发程序设计,网络程序设计,数据共享等。 Linux系统下的多线程遵循POSX线程接口,称为pthread (1)使用函数创建。 返回值:成功-0,失败-...
  • 问题描述: 五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有五只碗和五只...这个代表型的例子满足:在个进程之间分配个资源,而且不会出现死锁和饥饿。 问题解法 至多只允许四个哲学家同时进餐,
  • 简版服务器(c语言实现) (多线程)

    千次阅读 2016-09-11 11:23:33
    增加内容: 多线程,实现的是一个并发服务器。其中,用到了一把锁(pthread_mutex_t),用到了一个信号量(信号量的值为我规定的服务器处理队列长度值),然后就是将run函数里面的内容移植到void * thread(void * argc)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 594
精华内容 237
关键字:

多线程并发c语言

c语言 订阅