• 20155218 第八周学习总结+第八周测试+课下作业


    20155218 第八周学习总结+第八周测试+课下作业

    测试二:

    comd.c

    #include <stdio.h>
    #include<stdlib.h>
    #include<string.h>
    int main( int argc, char *argv[] ) {
    int sum=0;
    int i;
    for(i=0;i<argc;i++){
    sum += atoi(argv[i]);
    
    }
    printf("%d",sum);
    
    }
    

    otool -tV comd.o

    汇编代码:

    comd.o:
    (__TEXT,__text) section
    _main:
    0000000000000000	pushq	%rbp
    0000000000000001	movq	%rsp, %rbp
    0000000000000004	subq	$0x20, %rsp
    0000000000000008	movl	$_main, -0x4(%rbp)
    000000000000000f	movl	%edi, -0x8(%rbp)
    0000000000000012	movq	%rsi, -0x10(%rbp)
    0000000000000016	movl	$_main, -0x14(%rbp)
    000000000000001d	movl	$_main, -0x18(%rbp)
    0000000000000024	movl	-0x18(%rbp), %eax
    0000000000000027	cmpl	-0x8(%rbp), %eax
    000000000000002a	jge	0x55
    0000000000000030	movslq	-0x18(%rbp), %rax
    0000000000000034	movq	-0x10(%rbp), %rcx
    0000000000000038	movq	_main(%rcx,%rax,8), %rdi
    000000000000003c	callq	_atoi
    0000000000000041	addl	-0x14(%rbp), %eax
    0000000000000044	movl	%eax, -0x14(%rbp)
    0000000000000047	movl	-0x18(%rbp), %eax
    000000000000004a	addl	$0x1, %eax
    000000000000004d	movl	%eax, -0x18(%rbp)
    0000000000000050	jmp	0x24
    0000000000000055	leaq	0x18(%rip), %rdi ## literal pool for: "%d"
    000000000000005c	movl	-0x14(%rbp), %esi
    000000000000005f	movb	$0x0, %al
    0000000000000061	callq	_printf
    0000000000000066	movl	-0x4(%rbp), %esi
    0000000000000069	movl	%eax, -0x1c(%rbp)
    000000000000006c	movl	%esi, %eax
    000000000000006e	addq	$0x20, %rsp
    0000000000000072	popq	%rbp
    0000000000000073	retq
    

    y86:

    0x0000:                        | comd.o:
    0x0000:                        | (__TEXT,__text) section
    0x0000:                        | _main:
    0x0000:                        | 0000000000000000	pushq	%rbp
    0x0000:                        | 0000000000000001	movq	%rsp, %rbp
    0x0000:                        | 0000000000000004	subq	$0x20, %rsp
    0x0000:                        | 0000000000000008	movl	$_main, -0x4(%rbp)
    0x0000:                        | 000000000000000f	movl	%edi, -0x8(%rbp)
    0x0000:                        | 0000000000000012	movq	%rsi, -0x10(%rbp)
    0x0000:                        | 0000000000000016	movl	$_main, -0x14(%rbp)
    0x0000:                        | 000000000000001d	movl	$_main, -0x18(%rbp)
    0x0000:                        | 0000000000000024	movl	-0x18(%rbp), %eax
    0x0000:                        | 0000000000000027	cmpl	-0x8(%rbp), %eax
    0x0000:                        | 000000000000002a	jge	0x55
    0x0000:                        | 0000000000000030	movslq	-0x18(%rbp), %rax
    0x0000:                        | 0000000000000034	movq	-0x10(%rbp), %rcx
    0x0000:                        | 0000000000000038	movq	_main(%rcx,%rax,8), %rdi
    0x0000:                        | 000000000000003c	callq	_atoi
    0x0000:                        | 0000000000000041	addl	-0x14(%rbp), %eax
    0x0000:                        | 0000000000000044	movl	%eax, -0x14(%rbp)
    0x0000:                        | 0000000000000047	movl	-0x18(%rbp), %eax
    0x0000:                        | 000000000000004a	addl	$0x1, %eax
    0x0000:                        | 000000000000004d	movl	%eax, -0x18(%rbp)
    0x0000:                        | 0000000000000050	jmp	0x24
    0x0000:                        | 0000000000000055	leaq	0x18(%rip), %rdi ## literal pool for: "%d"
    0x0000:                        | 000000000000005c	movl	-0x14(%rbp), %esi
    0x0000:                        | 000000000000005f	movb	$0x0, %al
    0x0000:                        | 0000000000000061	callq	_printf
    0x0000:                        | 0000000000000066	movl	-0x4(%rbp), %esi
    0x0000:                        | 0000000000000069	movl	%eax, -0x1c(%rbp)
    0x0000:                        | 000000000000006c	movl	%esi, %eax
    0x0000:                        | 000000000000006e	addq	$0x20, %rsp
    0x0000:                        | 0000000000000072	popq	%rbp
                                   | 
    

    测试三:

    题目要求:

    基于socket 使用教材的csapp.h csapp.c,实现daytime(13)服务器(端口我们使用13+后三位学号)和客户端
    服务器响应消息格式是

    客户端IP:XXXX
    服务器实现者学号:XXXXXXXX
    当前时间: XX:XX:XX
    

    实现socket类似的代码在刘念老师的课上已经写过,但这次要求用课本的上的代码,所以我重新打了代码。
    查看代码容易发现需要我们修改的地方是:

    void echo(int connfd)
     44 {
     45     size_t n;
     46     char buf[MAXLINE];
     47     rio_t rio;
     48
     49     Rio_readinitb(&rio, connfd);
     50     while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
     51         printf("客户端IP:127.0.0.1
    ");
     52         printf("服务器实现学号:20155218
    ");
     53         printf("server received %d bytes
    ", n);
     54         time_t t;
     55         time(&t);
     56         printf("当前时间:%s
    ",ctime(&t));
     57         Rio_writen(connfd, buf, n);
     58     }
     59 }
    

    遇到的问题:

    在静态库连接的时候出现错误
    在寻求同学的帮助后,得知,

    结果:

    课下作业1

    .c:

    void bubble(int *data, int count) { 
    
    if(count == 0)
    return;
    int i, j;
    int *p, *q; 
    for(i=count-1; i!=0; i--){
    p = data, q = data + 1;
    for(j=0; j!=i; ++j)
    { 
    if( *p > *q )
    { 
    int t = *p;*p = *q;
    *q = t;
    } 
    p++, q++;}
    }}
    

    汇编代码:

    00000000 <bubble_p>:
       0:	56                   	push   %esi
       1:	53                   	push   %ebx
       2:	8b 44 24 10          	mov    0x10(%esp),%eax
       6:	8b 54 24 0c          	mov    0xc(%esp),%edx
       a:	8d 70 ff             	lea    -0x1(%eax),%esi
       d:	85 f6                	test   %esi,%esi
       f:	7e 2d                	jle    3e <bubble_p+0x3e>
      11:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
      18:	31 c0                	xor    %eax,%eax
      1a:	8d b6 00 00 00 00    	lea    0x0(%esi),%esi
      20:	8b 4c 82 04          	mov    0x4(%edx,%eax,4),%ecx
      24:	8b 1c 82             	mov    (%edx,%eax,4),%ebx
      27:	39 d9                	cmp    %ebx,%ecx
      29:	7d 07                	jge    32 <bubble_p+0x32>
      2b:	89 5c 82 04          	mov    %ebx,0x4(%edx,%eax,4)
      2f:	89 0c 82             	mov    %ecx,(%edx,%eax,4)
      32:	83 c0 01             	add    $0x1,%eax
      35:	39 f0                	cmp    %esi,%eax
      37:	7c e7                	jl     20 <bubble_p+0x20>
      39:	83 ee 01             	sub    $0x1,%esi
      3c:	75 da                	jne    18 <bubble_p+0x18>
      3e:	5b                   	pop    %ebx
      3f:	5e                   	pop    %esi
      
    Disassembly of section .text.startup:
    
    00000000 <main>:
       0:	31 c0                	xor    %eax,%eax
    

    y86:

    0x0000:                        | Disassembly of section .text:
                                   | 
    0x0000:                        | 00000000 <bubble_p>:
    0x0000:                        |    0:	56                   	push   %esi
    0x0000:                        |    1:	53                   	push   %ebx
    0x0000:                        |    2:	8b 44 24 10          	mov    0x10(%esp),%eax
    0x0000:                        |    6:	8b 54 24 0c          	mov    0xc(%esp),%edx
    0x0000:                        |    a:	8d 70 ff             	lea    -0x1(%eax),%esi
    0x0000:                        |    d:	85 f6                	test   %esi,%esi
    0x0000:                        |    f:	7e 2d                	jle    3e <bubble_p+0x3e>
    0x0000:                        |   11:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
    0x0000:                        |   18:	31 c0                	xor    %eax,%eax
    0x0000:                        |   1a:	8d b6 00 00 00 00    	lea    0x0(%esi),%esi
    0x0000:                        |   20:	8b 4c 82 04          	mov    0x4(%edx,%eax,4),%ecx
    0x0000:                        |   24:	8b 1c 82             	mov    (%edx,%eax,4),%ebx
    0x0000:                        |   27:	39 d9                	cmp    %ebx,%ecx
    0x0000:                        |   29:	7d 07                	jge    32 <bubble_p+0x32>
    0x0000:                        |   2b:	89 5c 82 04          	mov    %ebx,0x4(%edx,%eax,4)
    0x0000:                        |   2f:	89 0c 82             	mov    %ecx,(%edx,%eax,4)
    0x0000:                        |   32:	83 c0 01             	add    $0x1,%eax
    0x0000:                        |   35:	39 f0                	cmp    %esi,%eax
    0x0000:                        |   37:	7c e7                	jl     20 <bubble_p+0x20>
    0x0000:                        |   39:	83 ee 01             	sub    $0x1,%esi
    0x0000:                        |   3c:	75 da                	jne    18 <bubble_p+0x18>
    0x0000:                        |   3e:	5b                   	pop    %ebx
    0x0000:                        |   3f:	5e                   	pop    %esi
                                   |   
    0x0000:                        | Disassembly of section .text.startup:
                                   | 
    0x0000:                        | 00000000 <main>:
    0x0000:                        |    0:	31 c0                	xor    %eax,%eax
                                   |   
                                   |
    

    课下作业2

    要求:

    把课上练习3的daytime服务器分别用多进程和多线程实现成并发服务器并测试

    1.用多进程实现并发服务器:

    在并发的服务器中,父进程派生一个子进程来处理每一个新的连接请求。
    我们要包括一个SIGCHLD处理程序,来回收僵死进程的资源。父进程必须关闭它们各自的connfd副本。直到父子进程的connfd都关闭了,客户端的连接才会终止。

    在原有的代码的基础上做如下修改:

    while (1) {
    	connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);
    	if (Fork() == 0) { 
    	    Close(listenfd); /* Child closes its listening socket */
    	    echo(connfd);    /* Child services client */
    	    Close(connfd);   /* Child closes connection with client */
    	    exit(0);         /* Child exits */
    	}
    	Close(connfd); /* Parent closes connected socket (important!) */
        }
    

    运行结果:

    2.用线程实现并发服务器

    #include "csapp.h"
    
    void echo(int connfd);
    void *thread(void *vargp);
    
    int main(int argc, char **argv) 
    {
        int listenfd, *connfdp, port, clientlen=sizeof(struct sockaddr_in);
        struct sockaddr_in clientaddr;
        pthread_t tid; 
    
        if (argc != 2) {
    	fprintf(stderr, "usage: %s <port>
    ", argv[0]);
    	exit(0);
        }
        port = atoi(argv[1]);
    
        listenfd = Open_listenfd(port);
        while (1) {
    	connfdp = Malloc(sizeof(int));
    	*connfdp = Accept(listenfd, (SA *) &clientaddr, &clientlen);
    	Pthread_create(&tid, NULL, thread, connfdp);
        }
    }
    
    /* thread routine */
    void *thread(void *vargp) 
    {  
        int connfd = *((int *)vargp);
        Pthread_detach(pthread_self()); 
        Free(vargp);
        echo(connfd);
        Close(connfd);
        return NULL;
    }
    void echo(int connfd)
    {
        size_t n;
        char buf[MAXLINE];
        rio_t rio;
        
        Rio_readinitb(&rio, connfd);
        while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
            printf("客户端IP:127.0.0.1
    ");
            printf("服务器实现学号:20155218
    ");
            printf("server received %d bytes
    ", n);
            time_t t;
            time(&t);
            printf("当前时间:%s
    ",ctime(&t));
            Rio_writen(connfd, buf, n);
        }
    }
    
    
    

    实验结果:

    第八周学习总结

    I/O复用模型

    I/O复用原理:
    让应用程序可以同时对多个I/O端口进行监控以判断其上的操作是否可以进行,达到时间复用的目的。

    I/O多路复用的优劣:
    由于I/O多路复用是在单一进程的上下文中的,因此每个逻辑流程都能访问该进程的全部地址空间,所以开销比多进程低得多;缺点是编程复杂度高。

    多进程模型

    构造并发最简单的就是使用进程,像fork函数。例如,一个并发服务器,在父进程中接受客户端连接请求,然后创建一个新的子进程来为每个新客户端提供服务。

    多进程优点:
    每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;
    通过增加CPU,就可以容易扩充性能;
    可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系;
    每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大

    多进程缺点:
    逻辑控制复杂,需要和主程序交互;
    需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算

    多线程模型

    每个线程都有自己的线程上下文,包括一个线程ID、栈、栈指针、程序计数器、通用目的寄存器和条件码。所有的运行在一个进程里的线程共享该进程的整个虚拟地址空间。由于线程运行在单一进程中,因此共享这个进程虚拟地址空间的整个内容,包括它的代码、数据、堆、共享库和打开的文件。

    线程执行的模型:线程和进程的执行模型有些相似,每个进程的声明周期都是一个线程,我们称之为主线程。线程是对等的,主线程跟其他线程的区别就是它先执行。

    多线程的优点:
    无需跨进程边界;
    程序逻辑和控制方式简单;
    所有线程可以直接共享内存和变量等;
    线程方式消耗的总资源比进程方式好;

    多线程缺点:
    每个线程与主程序共用地址空间,受限于2GB地址空间;
    线程之间的同步和加锁控制比较麻烦;

    一个线程的崩溃可能影响到整个程序的稳定性;
    到达一定的线程数程度后,即使再增加CPU也无法提高性能,例如Windows Server 2003,大约是1500个左右的线程数就快到极限了(线程堆栈设定为1M),如果设定线程堆栈为2M,还达不到1500个线程总数;
    线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU

    Linux下不管是多线程编程还是多进程编程,最终都是用do_fork实现的多进程编程,只是进程创建时的参数不同,从而导致有不同的共享环境。Linux线程在核内是以轻量级进程的形式存在的,拥有独立的进程表项,而所有的创建、同步、删除等操作都在核外pthread库中进行。pthread 库使用一个管理线程(__pthread_manager() ,每个进程独立且唯一)来管理线程的创建和终止,为线程分配线程ID,发送线程相关的信号,而主线程pthread_create()) 的调用者则通过管道将请求信息传给管理线程。

    线程同步互斥及相关系统调用

    1. 临界区(Critical Section)适合一个进程内的多线程访问公共区域或代码段时使用。
    API: 
      VOID  EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);    //进入临界区 
      VOID  LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);   //离开临界区
    

    某一线程调用EnterCriticalSection函数进入临界区后,必须保证最后可以调用LeaveCriticalSection,否则公共区域无法释放,并被其它线程访问。
    在MFC中封装了CCriticalSection类,该类提供进入临界区和离开临界区的函数Lock()和Unlock()

    Ex: 
      CCriticalSection  cs;   //临界区对象 
      void  ThreadFunction() 
      { 
           cs.Lock(); 
          // 代码 
           cs.Unlock();         
       } //end ThreadFunction
    
    1. 互斥量 (Mutex):适合不同进程内多线程访问公共区域或代码段时使用,与临界区相似。
    HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName); 
       //创建一个互斥量,返回值为这个互斥量的句柄。参数bInitialOwner表示是否由调用此函数的进程拥有此互斥量 
      API: 
       HANDLE OpenMutex(DWORD dwDesiredAccess,BOOL hInheritHandle,LPCTSTR lpName);//打开一个已创建的互斥量 
       BOOL ReleaseMutex(HANDLE hMutex);   //释放 
       MFC中封装了CMutex类,同样的函数Lock()和Unlock()
    
    1. 事件(Event):通过线程间触发事件实现同步互斥
    API:  
       HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPCTSTR lpName);  //创建一个事件,返回值为事件句柄 参数bManualReset表示是否通过手动重设事件,参数为TRUE,则需要调用ResetEvent重设事件,否则为自动重设 
    HANDLE OpenEvent(DWORD dwDesizedAccess,BOOL bInheritHandle,LPCTSTR lpName);//打开事件
    

    在MFC中封装了CEvent类,包括SetEvent() 触发事件、PulseEvent 暂停事件、ResetEvent()重设事件及Unlock()释放事件句柄
    4. 信号量(Semaphore):与临界区和互斥量不同,可以实现多个线程同时访问公共区域数据,原理与操作系统中PV操作类似,先设置一个访问公共区域的线程最大连接数,每有一个线程访问共享区资源数就减一,直到资源数小于等于零。

    API: 
    HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES,LONG lInitialCount,LONG lMaxmemCount,LPCTSTR lpName); 
    //创建信号量,返回句柄,参数lInitialCount为信号量资源初始数基数,参数lMaxmemCount为该信号量的最大数 
    HANDLE OpenSemaphore(DWORD dwDesiredAccess,BOOL hInheriHandle,LPCTSTR lpName);//打开信号量 
    BOOL ReleaseSemaphore(HANDLE bSemaphore,LONG lReleaseCount,LPLONG lpPreviousCount); //释放信号量
    

    在MFC中封装了CSemaphore类,声明该类的对象后使用API:WaitForSingleObject()函数实现等待访问资源,使用ReleaseSemaphore函数释放资源,函数参数中需串入信号量对象句柄。
    总结:上述4个实现线程同步互斥的类均派生自虚基类CSyncObject,除临界区外其它3中方式均可用于多进程间线程同步互斥。
    另:线程触发自定义事件
    可使用API函数PostThreadMessage()函数,或创建CWinThread对象,调用该类的PostThreadMessage()

    1. 互斥锁是一种通过简单的加锁的方法来控制对共享资源的存取,用于解决线程间资源访问的唯一性问题。互斥锁有上锁和解锁两种状态,在同一时刻只能有一个线程掌握某个互斥的锁,拥有上锁状态的线程可以对共享资源进行操作。若其他线程希望对一个已经上了锁的互斥锁上锁,则该线程会被挂起,直到上锁的线程释放掉互斥锁为止。
      操作互斥锁的基本函数有:

    1

    .pthread_mutex_init
    

    ——互斥锁初始化;

    pthread_mutex_lock
    

    ——互斥锁上锁(阻塞版);

    pthread_mutex_trtylock
    

    ——互斥锁上锁(非阻塞版);

    pthread_mutex_unlock
    

    ——互斥锁解锁;

    pthread_mutex_destory
    

    ——消除互斥锁。
    线程互斥锁的数据类型是pthread_mutex_t,在使用前,要对其进行初始化,有以下两种方法:

    静态初始化:可以把常量PTHREAD_MUTEX_INITIALIZER赋给静态分配的互斥锁变量;
    动态初始化:在申请内存之后,通过pthread_mutex_init进行初始化,在释放内存前需要调用pthread_mutex_destroy。

    代码测试:
    (1)

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    
    // 打印机
    void printer(char *str)
    {
    	while(*str!='')
    	{
    		putchar(*str);	
    		fflush(stdout);
    		str++;
    		sleep(1);
    	}
    	printf("
    "); 
    }
    
    // 线程一
    void *thread_fun_1(void *arg)
    {
    	char *str = "hello";
    	printer(str); //打印
    }
    
    // 线程二
    void *thread_fun_2(void *arg)
    {
    	char *str = "world";
    	printer(str); //打印
    }
    
    int main(void)
    {
    	pthread_t tid1, tid2;
    	
    	// 创建 2 个线程
    	pthread_create(&tid1, NULL, thread_fun_1, NULL);
    	pthread_create(&tid2, NULL, thread_fun_2, NULL);
    
    	// 等待线程结束,回收其资源
    	pthread_join(tid1, NULL);
    	pthread_join(tid2, NULL); 
    	
    	return 0;
    }
    

    测试结果:

    输出混乱。

    添加互斥锁:

    #include <stdio.h>
    #include <pthread.h>
    #include <unistd.h>
    
    pthread_mutex_t mutex; //互斥锁
    
    // 打印机
    void printer(char *str)
    {
    	pthread_mutex_lock(&mutex); //上锁
    	while(*str!='')
    	{
    		putchar(*str);	
    		fflush(stdout);
    		str++;
    		sleep(1);
    	}
    	printf("
    "); 
    	pthread_mutex_unlock(&mutex); //解锁
    }
    
    // 线程一
    void *thread_fun_1(void *arg)
    {
    	char *str = "hello";
    	printer(str); //打印
    }
    
    // 线程二
    void *thread_fun_2(void *arg)
    {
    	char *str = "world";
    	printer(str); //打印
    }
    
    int main(void)
    {
    	pthread_t tid1, tid2;
    	
    	pthread_mutex_init(&mutex, NULL); //初始化互斥锁
    	
    	// 创建 2 个线程
    	pthread_create(&tid1, NULL, thread_fun_1, NULL);
    	pthread_create(&tid2, NULL, thread_fun_2, NULL);
    
    	// 等待线程结束,回收其资源
    	pthread_join(tid1, NULL);
    	pthread_join(tid2, NULL); 
    	
    	pthread_mutex_destroy(&mutex); //销毁互斥锁
    	
    	return 0;
    }
    

    输出结果:

  • 相关阅读:
    显示等待WebDriverWait
    MySQL添加注释
    linux
    linux时区问题
    CentOS禁用笔记本touchpad
    Mysql事务隔离级别
    IDEA集成有道翻译插件/maven帮助插件/mybatis插件
    SVN服务器的搭建和使用
    IntelliJ IDEA工具的安装使用
    IntelliJ IDEA的使用操作链接
  • 原文地址:https://www.cnblogs.com/xzh1996/p/7822129.html
Copyright © 2020-2023  润新知