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
                               | 

1071493-20171112172155653-1047097501.png

测试三:

题目要求:

基于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\n");
 52         printf("服务器实现学号:20155218\n");
 53         printf("server received %d bytes\n", n);
 54         time_t t;
 55         time(&t);
 56         printf("当前时间:%s\n",ctime(&t));
 57         Rio_writen(connfd, buf, n);
 58     }
 59 }
遇到的问题:

在静态库连接的时候出现错误1071493-20171111193243591-1191552943.png
在寻求同学的帮助后,得知,
1071493-20171111193515513-1644045358.png

结果:1071493-20171111193641372-1432416296.png

课下作业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
                               |   
                               |

1071493-20171112172155653-1047097501.png

课下作业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!) */
    }

运行结果:
1071493-20171111200753216-2038905091.png

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>\n", 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\n");
        printf("服务器实现学号:20155218\n");
        printf("server received %d bytes\n", n);
        time_t t;
        time(&t);
        printf("当前时间:%s\n",ctime(&t));
        Rio_writen(connfd, buf, n);
    }
}

实验结果:
1071493-20171112095737388-1795343463.png

第八周学习总结

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()释放事件句柄

  1. 信号量(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!='\0')
    {
        putchar(*str);  
        fflush(stdout);
        str++;
        sleep(1);
    }
    printf("\n"); 
}

// 线程一
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;
}

测试结果:
1071493-20171112092031497-855970991.png
输出混乱。

添加互斥锁:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

pthread_mutex_t mutex; //互斥锁

// 打印机
void printer(char *str)
{
    pthread_mutex_lock(&mutex); //上锁
    while(*str!='\0')
    {
        putchar(*str);  
        fflush(stdout);
        str++;
        sleep(1);
    }
    printf("\n"); 
    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;
}

输出结果:
1071493-20171112095037122-1867383522.png

转载于:https://www.cnblogs.com/xzh1996/p/7822129.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值