试题--创建三个进程/线程,依次输出 A、B、C

这是一道机试题,大概的预期执行结果如下图所示

最近刚好在学习linux编程,便使用多线程及多进程分别实现了一遍,其中多线程较为简单,使用0/1信号量在线程间实现生产者/消费者即可;多进程则稍微复杂一些,信号量必须设置为进程间通信,且存放在共享内存中,才能被多个进程访问。

多线程的实现代码如下:

  1 /*================================================================
  2  *   Copyright (C) 2019 Ltd. All rights reserved.
  3  *
  4  *   File Name :fork_test.c
  5  *   Author    :Hamilton
  6  *   Date      :2019-06-05
  7  *   Descriptor:
  8  *
  9  ================================================================*/
 10 
 11 
 12 #include <sys/types.h>
 13 #include <sys/wait.h>
 14 #include <unistd.h>
 15 #include <unistd.h>
 16 #include <stdio.h>
 17 #include <stdlib.h>
 18 #include <semaphore.h>
 19 #include <sys/mman.h>
 20 #include <sys/stat.h>        /* For mode constants */
 21 #include <fcntl.h>           /* For O_* constants */
 22 #include <stdbool.h>
 23 #include<pthread.h>
 24 
 25 #define SHARED_MEM_NAME "/PRINTABC"
 26 
 27 struct shared_memory {
 28     sem_t sem[3];
 29 };
 30 
 31 const char ch[] = {'A', 'B', 'C'};
 32 int fd_shm = -1;
 33 bool finish = false;
 34 struct shared_memory *shared_mem_ptr = NULL;
 35 
 36 void err_check(int ret)
 37 {
 38     if (ret < 0)
 39     {
 40         perror("error: %d. \n");
 41         exit(ret);
 42     }
 43 }
 44 
 45 void err_exit(char *str)
 46 {
 47     perror(str);
 48     exit(1);
 49 }
 50 
 51 void* thread_handler(void* arg)
 52 {
 53     int index = *(char*)arg - 'A';
 54     int pre = index ? (index - 1) : 2;
 55 
 56     usleep(100000);
 57 
 58     while (!finish)
 59     {
 60         sem_wait(&shared_mem_ptr->sem[pre]);
 61         printf("%c \n", ch[index]);
 62         sem_post(&shared_mem_ptr->sem[index]);
 63         usleep(100000);
 64     }
 65     pthread_exit(NULL);
 66 }
 67 
 68 void sig_handler(int signo)
 69 {
 70     if (signo == SIGINT)
 71     {
 72         printf("received SIGINT\n");
 73         finish = true;
 74     }
 75 }
 76 
 77 int main()
 78 {
 79     int err, i = 0;
 80 
 81     pthread_t tid[3];
 82 
 83     if (signal(SIGINT, sig_handler) == SIG_ERR)
 84         printf("\ncan't catch SIGINT\n");
 85 
 86     // Get shared memory
 87     if ((fd_shm = shm_open (SHARED_MEM_NAME, O_RDWR | O_CREAT, 0660)) < 0)
 88         err_exit ("shm_open");
 89 
 90     if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1)
 91         err_exit ("ftruncate");
 92 
 93     if ((shared_mem_ptr = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED,
 94                     fd_shm, 0)) == MAP_FAILED)
 95         err_exit ("mmap");
 96 
 97     err_check(sem_init(&shared_mem_ptr->sem[0], 0, 0));
 98     err_check(sem_init(&shared_mem_ptr->sem[1], 0, 0));
 99     err_check(sem_init(&shared_mem_ptr->sem[2], 0, 1));
100 
101     while(i < 3)
102     {
103         err = pthread_create(&(tid[i]), NULL, &thread_handler, (void*)&ch[i]);
104         if (err != 0)
105             printf("\ncan't create thread :[%s]", err);
106         else
107             printf("\n Thread created successfully\n");
108         i++;
109     }
110 
111     for (i = 0; i < 3; i++)
112     {
113         pthread_join(tid[i], NULL);
114         sem_destroy(&shared_mem_ptr->sem[i]);
115     }
116     shm_unlink(SHARED_MEM_NAME);
117     printf("all threads have finished.\n");
118     return 0;
119 }

 

 多进程的实现代码如下:

  1 /*================================================================
  2  *   Copyright (C) 2019 Ltd. All rights reserved.
  3  *
  4  *   File Name :fork_test.c
  5  *   Author    :Hamilton
  6  *   Date      :2019-06-05
  7  *   Descriptor:
  8  *
  9  ================================================================*/
 10 
 11 
 12 #include <sys/types.h>
 13 #include <sys/wait.h>
 14 #include <unistd.h>
 15 #include <unistd.h>
 16 #include <stdio.h>
 17 #include <stdlib.h>
 18 #include <semaphore.h>
 19 #include <sys/mman.h>
 20 #include <sys/stat.h>        /* For mode constants */
 21 #include <fcntl.h>           /* For O_* constants */
 22 #include <stdbool.h>
 23 
 24 #define SHARED_MEM_NAME "/PRINTABC"
 25 
 26 struct shared_memory {
 27     sem_t sem[3];
 28 };
 29 
 30 const char ch[] = {'A', 'B', 'C'};
 31 int fd_shm = -1;
 32 bool finish = false;
 33 struct shared_memory *shared_mem_ptr = NULL;
 34 
 35 void err_check(int ret)
 36 {
 37     if (ret < 0)
 38     {
 39         perror("error: %d. \n");
 40         exit(ret);
 41     }
 42 }
 43 
 44 void err_exit(char *str)
 45 {
 46     perror(str);
 47     exit(1);
 48 }
 49 
 50 void process_handler(int index)
 51 {
 52     int pre = index ? (index - 1) : 2;
 53 
 54     while (!finish)
 55     {
 56         sem_wait(&shared_mem_ptr->sem[pre]);
 57         printf("%c \n", ch[index]);
 58         sem_post(&shared_mem_ptr->sem[index]);
 59         usleep(100000);
 60     }
 61 }
 62 
 63 void sig_handler(int signo)
 64 {
 65     if (signo == SIGINT)
 66     {
 67         printf("received SIGINT\n");
 68         finish = true;
 69     }
 70 }
 71 
 72 int main()
 73 {
 74     pid_t pid;
 75 
 76     if (signal(SIGINT, sig_handler) == SIG_ERR)
 77         printf("\ncan't catch SIGINT\n");
 78 
 79     // Get shared memory
 80     if ((fd_shm = shm_open (SHARED_MEM_NAME, O_RDWR | O_CREAT, 0660)) < 0)
 81         err_exit ("shm_open");
 82 
 83     if (ftruncate (fd_shm, sizeof (struct shared_memory)) == -1)
 84         err_exit ("ftruncate");
 85 
 86     if ((shared_mem_ptr = mmap (NULL, sizeof (struct shared_memory), PROT_READ | PROT_WRITE, MAP_SHARED,
 87                     fd_shm, 0)) == MAP_FAILED)
 88         err_exit ("mmap");
 89 
 90     err_check(sem_init(&shared_mem_ptr->sem[0], 1, 0));
 91     err_check(sem_init(&shared_mem_ptr->sem[1], 1, 0));
 92     err_check(sem_init(&shared_mem_ptr->sem[2], 1, 1));
 93 
 94     pid = fork();
 95 
 96     if (pid < 0)
 97     {
 98         printf("Fork error.\n\n");
 99         exit(0);
100     }
101     else if (pid == 0)
102     {
103         printf("Process A, pid[%d]. \n", (int)getpid());
104         usleep(10000);
105         process_handler(0);
106     }
107     else
108     {
109         pid = fork();
110 
111         if (pid < 0)
112         {
113             printf("Fork error.\n\n");
114             exit(0);
115         }
116         else if (pid == 0)
117         {
118             printf("Process B, pid[%d]. \n", (int)getpid());
119             process_handler(1);
120         }
121         else
122         {
123             printf("Process C, pid[%d]. \n", (int)getpid());
124             process_handler(2);
125             wait(NULL);
126             sem_destroy(&shared_mem_ptr->sem[0]);
127             sem_destroy(&shared_mem_ptr->sem[1]);
128             sem_destroy(&shared_mem_ptr->sem[2]);
129             shm_unlink(SHARED_MEM_NAME);
130             printf("all processes have finished.\n");
131         }
132     }
133     return 0;
134 }

 

 

编译命令为:

gcc threadabc.c -o threadabc -lpthread -lrt

或者

  gcc forkabc.c -o forkabc -lpthread -lrt

 

 

因使用到了多线程/进程,需连接 -lpthread;使用到了POSIX的信号量/共享内存相关,则需要连接 -lrt。关于linux多线程/多进程的开发及API接口的使用,可翻阅我近期摘抄的一些文章。

 

运行结果:

pi@raspberrypi:~/code/ipc/print_abc $ ./threadabc

 Thread created successfully

 Thread created successfully

 Thread created successfully
A
B
C
A
B
C
A
B
C
^Creceived SIGINT
all threads have finished.
pi@raspberrypi:~/code/ipc/print_abc $ ./forkabc
Process C, pid[7883].
Process A, pid[7884].
Process B, pid[7885].
A
B
C
A
B
C
A
B
C
A
B
C
^Creceived SIGINT
received SIGINT
received SIGINT
all processes have finished.
pi@raspberrypi:~/code/ipc/print_abc $

 

转载于:https://www.cnblogs.com/miaoxiong/p/11158848.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.static有什么用途?(请至少说明两种) 1)在函数体,一个被声明为静态的变量在这一函数被调用过程维持其值不变。 2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用 2.引用与指针有什么区别? 1) 引用必须被初始化,指针不必。 2) 引用初始化以后不能被改变,指针可以改变所指的对象。 3) 不存在指向空值的引用,但是存在指向空值的指针。 3.描述实时系统的基本特性 在特定时间内完成特定的任务,实时性与可靠性。 4.全局变量和局部变量在内存是否有区别?如果有,是什么区别? 全局变量储存在静态数据库,局部变量在堆栈。 5.什么是平衡二叉树? 左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1。 6.堆栈溢出一般是由什么原因导致的? 没有回收垃圾资源。 7.什么函数不能声明为虚函数? constructor函数不能声明为虚函数。 8.冒泡排序算法的时间复杂度是什么? 时间复杂度是O(n^2)。 9.出float x 与“零值”比较的if语句。 if(x>0.000001&&x<-0.000001) 10.Internet采用哪种网络协议?该协议的主要层次结构? Tcp/Ip协议 主要层次结构为: 应用层/传输层/网络层/数据链路层/物理层。 11.Internet物理地址和IP地址转换采用什么协议? ARP (Address Resolution Protocol)(地址解析協議) 12.IP地址的编码分为哪俩部分? IP地址由两部分组成,网络号和主机号。不过是要和“子网掩码”按位与上之后才能区分哪些是网络位哪些是主机位。 13.用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出出C程序。 循环链表,用取余操作做 14.不能做switch()的参数类型是: switch的参数不能为实型。 1.出判断ABCD四个表达式的是否正确, 若正确, 出经过表达式 a的值(3分) int a = 4; (A)a += (a++); (B) a += (++a) ;(C) (a++) += a;(D) (++a) += (a++); a = ? 答:C错误,左侧不是一个有效变量,不能赋值,可改为(++a) += a; 改后答案依次为9,10,10,11 2.某32位系统下, C++程序,请计算sizeof 的值(5分). char str[] = “http://www.ibegroup.com/” char *p = str ; int n = 10; 请计算 sizeof (str ) = ?(1) sizeof ( p ) = ?(2) sizeof ( n ) = ?(3) void Foo ( char str[100]){ 请计算 sizeof( str ) = ?(4) } void *p = malloc( 100 ); 请计算 sizeof ( p ) = ?(5) 答:(1)17 (2)4 (3) 4 (4)4 (5)4 3. 回答下面的问题. (4分) (1).头文件的 ifndef/define/endif 干什么用?预处理 答:防止头文件被重复引用 (2). #i nclude 和 #i nclude “filename.h” 有什么区别? 答:前者用来包含开发环境提供的库头文件,后者用来包含自己编的头文件。 (3).在C++ 程序调用被 C 编译器编译后的函数,为什么要加 extern “C”声明? 答:函数和变量被C++编译后在符号库的名字与C语言的不同,被extern "C"修饰的变 量和函数是按照C语言方式编译和连接的。由于编译后的名字不同,C++程序不能直接调 用C 函数。C++提供了一个C 连接交换指定符号extern“C”来解决这个问题。 (4). switch()不允许的数据类型是? 答:实型 4. 回答下面的问题(6分) (1).Void GetMemory(char **p, int num){ *p = (char *)malloc(num); } void Test(void){ char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); } 请问运行Test 函数会有什么样的结果? 答:输出“hello” (2). void Test(void){ char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL){ strcpy(str, “world”); printf(str); } } 请问运行Test 函数会有什么样的结果? 答:输出“world” (3). char *GetMemory(void){ char p[] = "hello world"; return p; } void Test(void){ char *str = NULL; str = GetMemory(); printf(str); } 请问运行Test 函数会有什么样的结果? 答:无效的指针,输出不确定 5. 编strcat函数(6分) 已知strcat函数的原型是char *strcat (char *strDest, const char *strSrc); 其strDest 是目的字符串,strSrc 是源字符串。 (1)不调用C++/C 的字符串库函数,请编函数 strcat 答: VC源码: char * __cdecl strcat (char * dst, const char * src) { char * cp = dst; while( *cp ) cp++; /* find end of dst */ while( *cp++ = *src++ ) ; /* Copy src to end of dst */ return( dst ); /* return dst */ } (2)strcat能把strSrc 的内容连接到strDest,为什么还要char * 类型的返回值? 答:方便赋值给其他变量 6.MFCCString是类型安全类么? 答:不是,其它数据类型转换到CString可以使用CString的成员函数Format来转换 7.C++为什么用模板类。 答:(1)可用来创建动态增长和减小的数据结构 (2)它是类型无关的,因此具有很高的可复用性。 (3)它在编译时而不是运行时检查数据类型,保证了类型安全 (4)它是平台无关的,可移植性 (5)可用于基本数据类型 8.CSingleLock是干什么的。 答:同步多个线程一个数据类的同时访问 9.NEWTEXTMETRIC 是什么。 答:物理字体结构,用来设置字体的高宽大小 10.程序什么时候应该使用线程,什么时候单线程效率高。 答:1.耗时的操作使用线程,提高应用程序响应 2.并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。 3.多CPU系统使用线程提高CPU利用率 4.改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独 立的运行部分,这样的程序会利于理解和修改。 其他情况都使用线程。 11.Windows是内核级线程么。 答:见下一题 12.Linux有内核级线程么。 答:线程通常被定义为一个进程代码的不同执行路线。从实现方式上划分,线程有两 种类型:“用户级线程”和“内核级线程”。 用户线程指不要内核支持而在用户程序 实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度 和管理线程的函数来控制用户线程。这种线程甚至在象 DOS 这样的操作系统也可实现 ,但线程的调度要用户程序完成,这有些类似 Windows 3.x 的协作式多任务。另外一 种则要内核的参与,由内核完成线程的调度。其依赖于操作系统核心,由内核的内部 求进行创建和撤销,这两种模型各有其好处和缺点。用户线程要额外的内核开支 ,并且用户态线程的实现方式可以被定制或修改以适应特殊应用的要求,但是当一个线 程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不 到运行的机会;而内核线程则没有各个限制,有利于发挥多处理器的并发优势,但却占 用了更多的系统开支。 Windows NT和OS/2支持内核线程。Linux 支持内核级的多线程 13.C++什么数据分配在栈或堆,New分配数据是在近堆还是远堆? 答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理 堆: 程序运行时动态申请,new 和 malloc申请的内存就在堆上 14.使用线程是如何防止出现大的波峰。 答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提 高调度效率和限制资源使用的好处,线程线程达到最大数时,其他线程就会排队 等候。 15函数模板与类模板有什么区别? 答:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化 必须由程序员在程序显式地指定。 16一般数据库若出现日志满了,会出现什么情况,是否还能使用? 答:只能执行查询等读操作,不能执行更改,备份等操作,原因是任何操作都要记 录日志。也就是说基本上处于不能使用的状态。 17 SQL Server是否支持行级锁,有什么好处? 答:支持,设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据 的一致性和准确性,行级封锁确保在用户取得被更新的行到该行进行更新这段时间内不 被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。 18如果数据库满了会出现什么情况,是否还能使用? 答:见16 19 关于内存对齐的问题以及sizof()的输出 答:编译器自动对齐的原因:为了提高程序的性能,数据结构(尤其是栈)应该尽可能 地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器要作两次内存访问 ;然而,对齐的内存访问仅要一次访问。 20 int i=10, j=10, k=3; k*=i+j; k最后的值是? 答:60,此题考察优先级,实际成: k*=(i+j);,赋值运算符优先级最低 21.对数据库的一张表进行操作,同时要对另一张表进行操作,如何实现? 答:将操作多个表的操作放入到事务进行处理 22.TCP/IP 建立连接的过程?(3-way shake) 答:在TCP/IP协议,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。   第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状 态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个 SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;   第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1) ,此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。 23.ICMP是什么协议,处于哪一层? 答:Internet控制报文协议,处于网络层(IP层) 24.触发器怎么工作的? 答:触发器主要是通过事件进行触发而被执行的,当对某一表进行诸如UPDATE、 INSERT 、 DELETE 这些操作时,数据库就会自动执行触发器所定义的SQL 语句,从而确保对数 据的处理必须符合由这些SQL 语句所定义的规则。 25.winsock建立连接的主要实现步骤? 答:服务器端:socker()建立套接字,绑定(bind)并监听(listen),用accept() 等待客户端连接。 客户端:socker()建立套接字,连接(connect)服务器,连接上后使用send()和recv( ),在套接字上读数据,直至数据交换完毕,closesocket()关闭套接字。 服务器端:accept()发现有客户端连接,建立一个新的套接字,自身重新开始等待连 接。该新产生的套接字使用send()和recv()读数据,直至数据交换完毕,closesock et()关闭套接字。 26.动态连接库的两种方式? 答:调用一个DLL的函数有两种方法: 1.载入时动态链接(load-time dynamic linking),模块非常明确调用某个导出函数 ,使得他们就像本地函数一样。这要链接时链接那些函数所在DLL的导入库,导入库向 系统提供了载入DLL时所的信息及DLL函数定位。 2.运行时动态链接(run-time dynamic linking),运行时可以通过LoadLibrary或Loa dLibraryEx函数载入DLL。DLL载入后,模块可以通过调用GetProcAddress获取DLL函数的 出口地址,然后就可以通过返回的函数指针调用DLL函数了。如此即可避免导入库文件了 。 27.IP组播有那些好处? 答:Internet上产生的许多新的应用,特别是高带宽的多媒体应用,带来了带宽的急剧 消耗和网络拥挤问题。组播是一种允许一个或多个发送者(组播源)发送单一的数据包 到多个接收者(一次的,同时的)的网络技术。组播可以大大的节省网络带宽,因为无 论有多少个目标地址,在整个网络的任何一条链路上只传送单一的数据包。所以说组播 技术的核心就是针对如何节约网络资源的前提下保证服务质量。
这是书的光盘。共分为两个部分,这是第一部分。 本书由浅入深、循序渐进地介绍了Windows驱动程序的开发方法与调试技巧。本书共分23章,内容涵盖了 Windows操作系统的基本原理、NT驱动程序与WDM驱动程序的构造、驱动程序的同步异步处理方法、驱 动程序即插即用功能、驱动程序的各种调试技巧等。同时,还针对流行的PCI驱动程序、USB驱动程序 、虚拟串口驱动程序、摄像头驱动程序、SDIO驱动程序进行了详细的介绍,本书最大的特色在于每一节 的例子都是经过精挑细选的,具有很强的针对性。力求让读者通过亲自动手实验,掌握各类Windows驱动 程序的开发技巧,学习尽可能多的Windows底层知识。   本书适用于、高级系统程序员,同时也可用做高校计算机专业操作系统实验课的补充教材。 原创经典,威盛一线工程师倾力打造。深入驱动核心,剖析操作系统底层运行机制,通过实例引导,快 速学习编译、安装、调试的方法。   从Windows最基本的两类驱动程序的编译、安装、调试入手讲解,非常容易上手,用实例详细讲解 PCI、USB、虚拟串口、虚拟摄像头、SDIO等驱动程序的开发,归纳了多种调试驱动程序的高级技巧,如 用WinDBG和VMWARE软件对驱动进行源码级调试,深入Windows操作系统的底层和内核,透析Windows驱动 开发的本质。 本书是作者结合教学和科研实践经验编而成的,不仅详细介绍了Windows内核原理,而且介绍了编程技 巧和应用实例,兼顾了在校研究生和工程技术人员的实际求,对教学、生产和科研有现实的指导意义 ,是一本值得推荐的专著。              ——国工程院院士   院士推荐   目前,电子系统设计广泛采用通用操作系统,达到降低系统的设计难度和缩短研发周期。实现操作 系统与硬件快速信息交换是电子系统设计的关键。   通用操作系统硬件驱动程序的开发,编者不仅要精通硬件设备、计算机总线,而且要Windows 操作系统知识以及调试技巧。学习和掌握Windows硬件驱动程序的开发是电子系统设计人员必备的能力。   本书是作者结合教学和科研实践经验编而成的,不仅详细介绍了Windows内核原理,并且介绍了编 程技巧和应用实例,兼顾了在校研究生和工程技术人员的实际求,对教学、生产和科研有现实的指导 意义,是一本值得推荐的专著。 第1篇 入门篇 第1章 从两个最简单的驱动谈起 本章向读者呈现两个最简单的Windows驱动程序一个是NT式的驱动程序,另一个是WDM式的驱动程序。 这两个驱动程序没有操作具体的硬件设备,只是在系统里创建了虚拟设备。在随后的章节,它们会作 为基本驱动程序框架,被本书其他章节的驱动程序开发所复用。笔者将带领读者编代码、编译、安装 和调试程序。   1.1 DDK的安装   1.2 第一个驱动程序HelloDDK的代码分析    1.2.1 HelloDDK的头文件    1.2.2 HelloDDK的入口函数    1.2.3 创建设备例程    1.2.4 卸载驱动例程    1.2.5 默认派遣例程   1.3 HelloDDK的编译和安装    1.3.1 用DDK环境编译HelloDDK    1.3.2 用VC集成开发环境编译HelloDDK    1.3.3 HelloDDK的安装   1.4 第二个驱动程序HelloWDM的代码分析    1.4.1 HelloWDM的头文件    1.4.2 HelloWDM的入口函数    1.4.3 HelloWDM的AddDevice例程    1.4.4 HelloWDM处理PNP的回调函数    1.4.5 HelloWDM对PNP的默认处理    1.4.6 HelloWDM对IRP_MN_REMOVE_DEVICE的处理    1.4.7 HelloWDM对其他IRP的回调函数    1.4.8 HelloWDM的卸载例程   1.5 HelloWDM的编译和安装    1.5.1 用DDK编译环境编译HelloWDM    1.5.2 HelloWDM的编译过程    1.5.3 安装HelloWDM   1.6 小结  第2章 Windows操作驱动的基本概念  驱动程序操作系统加载在内核模式下,它与Windows操作系统内核的其他组件进行密切交互。本章主 要介绍Windows操作系统内核的基本概念,同时还介绍应用程序和驱动程序之间的通信方法。   2.1 Windows操作系统概述    2.1.1 Windows家族    2.1.2 Windows特性    2.1.3 用户模式和内核模式    

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值