• 面试题——蓝


    1. 可重入是什么概念?

    可重入代码(Reentry code)也叫纯代码(Pure code)是一种允许多个进程同时访问的代码。为了使各进程所执行的代码完全相同,故不允许任何进程对其进行修改。程序在运行过程中可以被打断,并由开始处再次执行,并且在合理的范围内(多次重入,而不造成堆栈溢出等其他问题),程序可以在被打断处继续执行,且执行结果不受影响。

    (不应该有全局变量或静态变量,因为这些变量会保存某一个进程的修改。可重入代码中的变量应该都是局部变量,每次重新调用时变量重新被赋值,从而保证,每个进程对它的访问都产生同样的结果。)

    void test()
    {
      int i;
      i=2;
      printf("%d ",i );
      i++;
      printf("%d ",i);
    }
    结果:每次都是:2 3
    void test()
    {
      static int i=2;
      printf("%d ",i );
      i++;
      prinft("%d ",i);
    }
    结果:第一次:2 3;第二次:3  4
     

    2. 如何确保代码可重入?

    若一个程序或子程序可以安全的被并行执行,则称其为可重入(reentrant或re-entrant)的;即,当该子程序正在运行时,可以再次进入并执行它。
    若一个函数是可重入的,则该函数:
    不能含有静态(全局)非常量数据。 不能返回静态(全局)非常量数据的地址。 只能处理由调用者提供的数据。 不能依赖于单实例模式资源的锁。 不能调用不可重入的函数。 多 '用户/对象/进程优先级' 以及多进程一般会使得对可重入代码的控制变得复杂。同时,IO代码通常不是可重入的,因为他们依赖于像磁盘这样共享的、单独的资源。
     
    3. 进程间通讯方式?线程间通讯方式?
    进程间:管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
        有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
        信号量(semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
        消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
        信号 (sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
        共享内存(shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
        套接字(socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
    线程间通信可以通过下列三种方法:  1)使用全局变量实现线程间通信  2)使用消息实现线程间通信  3)使用CEvent类实现线程间通信
    MFC下常用方法:
    1.全局变量  注:定义全局变量时最好使用volatile来定义,以防编译器对此变量进行优化。
    2.Message消息机制,常用的Message通信的接口主要有两个:PostMessage为线程向主窗口发送消息。而PostThreadMessage是任意两个线程之间的通信接口。
    3.CEvent对象,是MFC中的一个对象,可以通过对CEvent的触发状态进行改变,从而实现线程间的通信和同步。
    线程间同步机制:锁机制:包括互斥锁、条件变量、读写锁(或者说 互斥mutex、信号量Semaphore、临界区Critical section)
        互斥锁提供了以排他方式防止数据结构被并发修改的方法。
        读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
        条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
        信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
        信号机制(Signal):类似进程间的信号处理
      线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。
     
    4. volatile关键词含义?————直接存取原始内存地址
    volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
    volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.就是防止编译器对代码进行优化
    常用于:1)并行设备的硬件寄存器(如:状态寄存器)
        2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 
        3)多线程应用中被几个任务共享的变量
      1).一个参数既可以是const还可以是volatile吗?是的。只读的状态寄存器。是volatile因为它可能被意想不到地改变,是const因为程序不应该试图去修改它。
      2). 一个指针可以是volatile 吗?是的。如:当一个中断服务子程序修改一个指向一个buffer的指针时。
      3). 下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?  intsquare(volatileint*ptr)  {  return*ptr**ptr;  }
      *ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!
     
    5. 关键字static作用?与关键字extern的区别?

      1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
      2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
      3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

      (本地化数据和代码范围的好处和重要性)

      extern和static完全不同,static会定义一个变量,extern不能定义一个变量,extern表示的是“已经存在一个变量,但是不在当前的编译单元内,需要在其他编译单元中寻找。
      文件a.c
      static int i;   //只在a文件中用
      int j;            //在工程里用
      static void init(){}  //只在a文件中用
      void callme()          //在工程中用
      {static int sum;}

      上面的全局 i 变量和 init() 函数只能用在a.c文件中,全局变量sum的作用域只在callme里。

      变量j和函数callme()的全局限扩充到整个工程文件。

      所以可以在下面的b.c中用extern关键字调用。extern告诉编译器这个变量或者函数在其他文件里已经被定义了。

      文件b.c
      extern int j;                //调用a文件里的
      extern void callme();   //调用a文件里的
      int main(){}

        extern的另外用法是当C和C++混合编程时如果c++调用的是c源文件定义的函数或者变量,那么要加extern来告诉编译器用c方式命名函数:

        文件A.cpp调用a.c里面的变量i和函数callme()
        extern "C"  //在c++文件里调用c文件中的变量
        {  int j;  void callme();  }
        int main()
        {  callme();  }
     
    6. 查看当前目录下是否存在一个叫abc的文件
      VB——if dir("c:a.txt")<>"" then  存在 endif
      php——<?php   $filename = '/path/to/foo.txt'; if (file_exists($filename))
          { echo "The file $filename exists"; }
          else { echo "The file $filename does not exist"; } ?> 
      Linux下  ( if access(const char* pathname, F_OK)==0)  存在 (F_OK文件是否存在  R_OK读权限  W_OK写权限  X_OK执行权限
           ( if opendir(const char* pathname)==0)  存在(不存在 NULL)
          find -name "$(date +%F)*" -exec mv {} ./history ;发现当前目录下有用当天日期为文件名的文件,即做MV
      C++  #include <iostream>  #include <fstream>  using namespace std;  #define FILENAME "stat.dat"
            int main(){     fstream _file;     _file.open(FILENAME,ios::in);     
              if(!_file)     {  cout<<FILENAME<<"没有被创建";  }
                 else  {  cout<<FILENAME<<"已经存在";}  return 0;  } 
      C语言  #include  <io.h>  #include  <stdio.h>  #include  <stdlib.h>
            void main( void ) { if( (_access( "ACCESS.C", 0 )) != -1 ) { printf( "File ACCESS.C exists " );    
                       if(   (_access( "ACCESS.C", 2 )) != -1 )      printf( "File ACCESS.C has write permission " );   }  }
     
    7. 嵌入式系统常对寄存器或变量进行位操作,给定一个整形变量value,设置value的bit 3,清除value的bit 3,以上操作保持其它位不变
      value |=0x01<<3  ;  value &=-(0x01<<3)
     
    8. 嵌入式系统访问某特定内存位置,32位机要求设置一绝对地址为0x000067a9的整形变量值为0xaa66,代码完成
      若这个地址是代码段(方法)位置,且已知函数为void型,无参,如何调用?
      1) int* p;  p=0x000067a9;  *p=0xaa66  2)  void (*p)();声明  p=0x000067a9;定义  *p();调用
     
     
  • 相关阅读:
    easyui学习笔记1—增删改操作
    sql点滴37—mysql中的错误Data too long for column '' at row 1
    javascript获取当前url
    escape()、encodeURI()、encodeURIComponent()区别详解
    js文本框提示和自动完成
    javascript js string.Format()收集
    超链接标签为什么会造成页面颤抖
    asp.net mvc 4.0常见的几个问题
    如何使用Flashfxp上传下载文件
    点击按钮显示谷歌地图
  • 原文地址:https://www.cnblogs.com/qq1129496211/p/4072218.html
Copyright © 2020-2023  润新知