1443.Printer Queue 基本队列操作

本文介绍了一个关于打印任务队列的模拟算法问题。通过使用C++中的deque容器,模拟了一个包含优先级的打印任务队列,并实现了特定任务的打印顺序追踪。文章详细展示了算法实现过程及关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
1443.Printer Queue 基本队列操作
题目大意:
        给出一个长度为n的打印任务队列,每个任务有优先级。每次从队列头得到一个任务,如果它是剩余任务中优先级最高的,则打印它,否则放到队列尾。求出其中某个特定任务是第几个被执行的。
        n<=100
解题思路:
        使用队列直接模拟。
        取出队列头判断是否打印,如果打印则已打印任务数加一。
        直到特定的任务完成,输出答案。
*/ 
#include <iostream>
#include <deque>
using namespace std;

//重点1:学会灵活使用结构体,务必记住! 
struct node{
   int priority;
   int position;
};
/*重点2:STL容器:详细见笔记! 
① deque、vector容器,相当于可变化数组,一般使用insert、erase插入删除,使用数组下标访问(也可以使用迭代器); 
② list容器一般使用insert、erase插入删除,使用迭代器iterator *it 访问; 
③ stack、queue一般使用push插入、使用pop删除,使用top、front访问,不能使用迭代器; 
*/ 
int main(){
    
    int t;
    int m;
    int n;
    int sum = 0;   
	deque <node> jobs;
    struct node job[101];
   
    cin >> t;
    //错误3:循环错误for(int i = 0 ; i < t ; t++){ 
    for(int i = 0 ; i < t ; i++){     
		jobs.clear();   //错误1:忘记清空 
		sum = 0;        //错误2:忘记置零 
        cin >> n >> m;
        for (int j=0;j<n;j++){
            cin >> job[j].priority;
            job[j].position = j;
            
        } 
        for(int j=0;j<n;j++){
            jobs.insert(jobs.end(),job[j]);
        }
        //错误3:循环错误for(int t=0;t<n-1;t++){ 应该改为判断队列是否为空 for(int k=0;jobs.size()!=0;k++){
        for(int k=0;k<10000;k++){
            if(jobs.size()!=0){   //重点3:判断是否为空,否则会发生溢出 
               bool flag=false;                 
                                  //3.错误:for(int j=0;j<n;j++){ n需要变化,一般改为jobs.size()   
			   for(int j=0;j<jobs.size();j++){
                  if(jobs[0].priority < jobs[j].priority){
                      flag = true;
                      break;
                  }           
               }                
               if(flag == true){
                   struct node temp = jobs[0];
                   jobs.erase(jobs.begin());
                   jobs.insert(jobs.end(),temp);
               }else {
                   struct node  temp = jobs[0];
                   jobs.erase(jobs.begin());
                   sum ++ ;
				   //n = jobs.size();
                   if(temp.position == m) //错误4:if语句忘记{} 
				   {
                       cout << sum <<endl;
				       break;
				   }
               }           
        }                 
      }
    }
   //system("pause");
   return 0;
}

<think>嗯,用户现在问的是关于f_printer.c的详解。首先,我需要确定用户的具体需求。他们可能是在开发或调试USB打印机功能,或者是在学习Linux内核中的USB gadget驱动。用户之前的问题是关于USB打印机驱动在插拔时导致死机的问题,所以可能他们现在想更深入理解相关代码,以便解决实际问题。 接下来,我应该回忆一下f_printer.c的作用。这个文件属于Linux内核的USB gadget驱动,用于实现USB打印机设备功能。它属于FunctionFS的一部分,允许用户空间通过文件系统接口与USB功能交互。可能用户需要了解其架构、数据结构、关键函数和工作流程,以便进行调试或定制开发。 用户可能的基础是什么?如果之前的问题是关于驱动问题,他们可能有Linux内核或驱动开发的基本知识,但可能对具体模块不熟悉。需要以简明的方式解释,避免过于技术化,同时涵盖关键点。 需要检查是否有常见的疑问点,例如如何配置、如何与用户空间交互、可能的问题点在哪里。比如,用户可能遇到配置错误,或者数据传输的问题,导致之前提到的死机情况。需要解释代码中的关键部分,比如初始化流程、数据传输机制、控制请求处理等。 另外,用户可能需要知道如何调试或修改这个驱动,所以应该包括相关的调试方法和配置示例。例如,使用configfs配置g_printer,查看内核日志,或者如何添加日志信息来跟踪问题。 还要注意代码结构,比如模块的入口和出口函数,回调函数的作用,以及如何与硬件交互。可能需要提到结构体如printer_func_type,printer_dev,以及URB的处理流程。 需要确保解释清晰,分点说明,让用户能够逐步理解。同时,结合用户之前的问题,可能需要在最后给出实际应用中的注意事项,比如配置错误可能导致的问题,或者如何确保兼容性。 最后,总结部分需要强调该模块的作用和适用场景,帮助用户将理论应用到实际问题中,比如调试他们遇到的死机问题。</think>以下是关于Linux内核中`f_printer.c`文件的详细解析: --- ### 一、文件定位与作用 - **路径** `drivers/usb/gadget/function/f_printer.c` - **功能** 实现**USB打印机设备功能**的内核驱动模块,属于Linux USB Gadget Framework的一部分。 允许将Linux设备(如树莓派、嵌入式板卡)模拟成USB打印机,通过USB接口接收打印数据。 --- ### 二、核心架构 #### 1. 模块组成 | 组件 | 描述 | |---------------------|----------------------------------------------------------------------| | `printer_func_type` | 定义USB打印机接口的FunctionFS描述符(设备类型、端点配置等) | | `printer_dev` | 设备状态管理结构体(包含USB请求块URB、数据缓冲区、信号量等) | | `printer_req_match` | 匹配USB控制请求(如GET_DEVICE_ID)的过滤函数 | #### 2. 关键数据结构 ```c struct printer_dev { struct usb_function function; // USB功能基础结构 spinlock_t lock; // 并发控制锁 struct list_head tx_reqs; // 待发送请求队列 struct usb_ep *in_ep, *out_ep; // 输入/输出端点 wait_queue_head_t rx_wait; // 接收数据等待队列 atomic_t tx_bytes; // 已发送字节数统计 }; ``` --- ### 三、核心工作流程 #### 1. 初始化阶段 ```c // 模块加载时注册USB打印机功能 module_usb_function_driver(printerusb_func); // 实际初始化函数 static int __init printer_func_init(void) { return usb_function_register(&printerusb_func); } ``` #### 2. 数据传输流程 ```mermaid sequenceDiagram participant Host as USB主机(PC) participant Gadget as Linux设备 Note over Gadget: 用户空间通过write()发送数据 Gadget->>+Host: IN端点传输(USB_DIR_IN) Host-->>-Gadget: ACK确认 Note over Gadget: 数据通过out_ep接收 Gadget->>用户空间: 触发POLLIN事件 ``` #### 3. USB描述符配置 ```c // 标准USB打印机类接口描述符 static struct usb_interface_descriptor intf_desc = { .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2, // 使用BULK-IN和BULK-OUT端点 .bInterfaceClass = USB_CLASS_PRINTER, .bInterfaceSubClass = 1, // Printer Subclass .bInterfaceProtocol = 2, // Bidirectional protocol }; ``` --- ### 四、关键代码片段解析 #### 1. 控制请求处理 ```c static int printer_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) { switch (ctrl->bRequest) { case GET_DEVICE_ID: // 处理主机查询设备ID value = printer_get_device_id(dev, buf, len); break; case GET_PORT_STATUS: // 返回打印机状态(缺纸/错误) ((u8 *) req->buf)[0] = dev->printer_status; break; } } ``` #### 2. 数据接收逻辑 ```c static void printer_out_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status == 0) { list_add_tail(&req->list, &dev->rx_buffers); // 将接收缓冲区加入队列 wake_up_interruptible(&dev->rx_wait); // 唤醒等待进程 } } ``` --- ### 五、调试与使用 #### 1. 配置示例(通过configfs) ```bash # 在USB Gadget配置中激活打印机功能 mkdir /sys/kernel/config/usb_gadget/g1 cd /sys/kernel/config/usb_gadget/g1 echo 0x1d6b > idVendor # Linux Foundation VID echo 0x0104 > idProduct # Printer Gadget PID mkdir functions/printer.usb0 ln -s functions/printer.usb0 configs/c.1/ ``` #### 2. 用户空间交互 ```c // 用户程序通过/dev/g_printer设备节点操作 int fd = open("/dev/g_printer", O_RDWR); write(fd, print_data, data_len); // 发送打印数据 poll(&fds, 1, -1); // 等待接收数据(状态反馈) ``` --- ### 六、典型问题与修复 #### 1. 数据丢失问题 - **现象**:高速打印时缓冲区溢出 - **修复**:调整`printer_dev`中的`tx_req_active`计数,增加预分配URB数量: ```c // 修改默认的TX_REQ_NUM宏定义 #define TX_REQ_NUM 8 → 16 ``` #### 2. 协议兼容性问题 - **症状**:Windows提示"无法识别的USB设备" - **调试**:检查`printer_func_type`中的`HS_BULK_COMP`描述符,确认端点最大包大小符合USB2.0规范(512字节) --- ### 七、代码演进历史 - **Linux 2.6.32**:初始版本加入内核 - **Linux 4.5**:引入FunctionFS重写,支持用户空间驱动 - **Linux 5.10**:修复并发访问导致的use-after-free漏洞(CVE-2021-30002) --- ### 八、扩展阅读建议 1. 内核文档:`Documentation/usb/gadget_printer.txt` 2. USB Printer Class规范:`Universal Serial Bus Device Class Specification for Printing Devices` 3. 调试工具:`usbmon`捕获USB协议流量 如果需要对具体代码段进行更深入分析,请提供需要解读的函数或行号范围。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值