K3 出现单据不能保存,并且事件中出现数据库pss->IsSingleThreaded

本文详细解析了在2003系统中遇到的SQL Server断言错误:文件:,行=1882,失败的断言=pss->IsSingleThreaded()。通过研究发现,问题在于服务器上安装的SQL SP4补丁版本号为8.00.203ServicePack4,并未修复此bug。解决方法是下载并安装最新版的SQL SP4补丁,版本号为8.00.2282SP4,补丁号为KB960083。

在2003系统中应用程序出现
错误:
17066:
SQL Server 断言: 文件: ,行 = 1882
失败的断言 =“pss->IsSingleThreaded ()”。
-------------------------------------------------

-------------------------------------------------
错误:
18052:
错误: 3624,严重度: 20,状态: 1。
一出现这个问题K3就不能保存

 

 

 

经过多天 的研究, 终于弄好了.
原因: 服务器上打的 SQL SP4 补丁版本号是 8.00.203 Service Pack 4, 此版本的 sP4 补丁中并没有解决此bug (楼主贴子中的问题). 见 http://www.aspfaq.com/sql2000builds.asp SQL 补丁 解决Bug 列表.
解决方法: 下载最新的SQL SP4 补丁 版本号是 8.00.2282 SP4 ,补丁号KB960083
下载地址:http://www.microsoft.com/downloads/details.aspx?familyid=A93F3CFE-18C9-4218-A551-13BF415E418A&displaylang=zh-cn

<think> 我们正在讨论的是libwebsockets中的`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调。根据用户的问题,他想了解这个回调中传递的“假的wsi”的原理、作用及相关情况。 首先,我们需要明确:在`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调中,传入的wsi(WebSocket连接实例)是NULL或者是一个“假的”wsi。这不是一个真正的客户端连接,而是一个特殊的标识。 ### 1. 回调触发原理 `LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调是在事件循环等待被外部事件(如信号、定时器、其他线程通知)中断时触发的。具体来说: - 当其他线程调用`lws_cancel_service()`时,它会中断事件循环的等待状态,并触发此回调。 - 由于这个回调不是由特定的客户端连接事件触发的,因此没有与之关联的wsi。 ### 2. 传递“假的wsi”的作用 在libwebsockets中,每个回调通常都会关联一个wsi,代表一个具体的连接。但`LWS_CALLBACK_EVENT_WAIT_CANCELLED`是一个全局事件,与特定连接无关。为了保持回调函数参数的一致性,libwebsockets传递了一个特殊的wsi,称为“假的wsi”(fake wsi)或虚拟wsi(virtual wsi)[^1][^2]。 这个假的wsi的作用包括: - **保持回调参数一致**:所有回调都有`struct lws *wsi`作为第一个参数,为了统一,即使没有具体连接,也传递一个非NULL的wsi(但它是特殊的)。 - **提供上下文**:通过这个假的wsi,可以获取到`lws_context`(通过`lws_get_context(wsi)`)和`vhost`(通过`lws_get_vhost(wsi)`)等信息,从而在回调中执行全局操作。 ### 3. 相关情况 在实际使用中,我们可以在`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调中执行以下操作: - **遍历所有连接**:由于没有具体连接,我们可以利用这个回调来遍历所有活动的连接,并执行一些操作(例如,标记所有连接为可写,以便发送数据)[^1]。 - **处理全局事件**:例如,当工作线程向环形缓冲区中放入数据后,通过`lws_cancel_service()`触发事件循环,然后在`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调中通知所有连接的wsi可写。 ### 4. 代码示例 参考用户提供的代码,在`callback_minimal`函数中: ```c case LWS_CALLBACK_EVENT_WAIT_CANCELLED: lwsl_notice("LWS_CALLBACK_EVENT_WAIT_CANCELLED in svc\n"); if (!vhd) break; // 遍历所有连接的客户端,标记为可写 lws_start_foreach_llp(struct per_session_data__minimal **, ppss, vhd->pss_list) { lws_callback_on_writable((*ppss)->wsi); } lws_end_foreach_llp(ppss, pss_list); break; ``` 在这个例子中,我们并没有使用传入的wsi(实际上它是假的),而是使用vhd(每个虚拟主机的数据)中的客户端连接链表,对每个客户端连接调用`lws_callback_on_writable`。 ### 5. 注意事项 - **假的wsi不是真正的连接**:因此,不能在这个wsi上进行数据发送等操作。 - **获取全局信息**:通过`lws_get_context(wsi)`可以获取到全局上下文,从而访问全局数据。 ### 总结 `LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调中传递的“假的wsi”是libwebsockets为了保持回调函数参数一致性而设计的机制。它允许开发者在这个全局事件中获取上下文并执行全局操作,如遍历所有连接并触发写操作。在实际使用中,我们通常忽略这个wsi的具体连接属性,而关注其提供的上下文信息[^1][^2]。 §§相关问题§§ 1. 在`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调中,除了标记连接可写,还能执行哪些操作? 2. 如何安全地在多线程环境中使用`lws_cancel_service()`? 3. 假的wsi在libwebsockets内部是如何创建和管理的? </think> ### LWS_CALLBACK_EVENT_WAIT_CANCELLED回调中"假wsi"机制详解 在libwebsockets中,`LWS_CALLBACK_EVENT_WAIT_CANCELLED`回调使用的"假wsi"(WebSocket连接实例)是libwebsockets框架设计的一种**特殊事件通知机制**,其原理和作用如下: --- ### 1. 实现原理 ```mermaid graph LR A[工作线程] -->|lws_cancel_service| B[事件循环] B -->|触发| C[LWS_CALLBACK_EVENT_WAIT_CANCELLED] C -->|传递| D[假wsi] D --> E[全局操作] ``` - **虚假性本质**:该wsi不关联任何实际客户端连接,仅作为事件载体 - **框架内部构造**:由libwebsockets内部创建的特殊wsi实例 - **标识特征**:`wsi->context`有效但`wsi->vhost`为NULL --- ### 2. 核心作用 #### 2.1 事件通知通道 ```c // 工作线程中 lws_cancel_service(vhd->context); // 回调中 case LWS_CALLBACK_EVENT_WAIT_CANCELLED: // 使用假wsi作为通知载体 ``` - 提供线程间通信通道(工作线程→服务线程) - 避免直接操作真实连接对象引发线程安全问题[^2] #### 2.2 全局状态更新 ```c lws_start_foreach_llp(struct per_session_data__minimal **, ppss, vhd->pss_list) { lws_callback_on_writable((*ppss)->wsi); // 标记真实连接可写 } ``` - 触发所有真实连接的写操作准备 - 实现广播式事件分发(如环形缓冲区有新数据时) #### 2.3 上下文访问 ```c struct lws_context *ctx = lws_get_context(wsi); struct per_vhost_data__minimal *vhd = lws_protocol_vh_priv_get(lws_get_vhost(wsi), protocol); ``` - 通过假wsi获取全局`lws_context` - 访问协议特定的虚拟主机数据(如示例中的环形缓冲区) --- ### 3. 关键特性 #### 3.1 线程安全设计 ```c // 假wsi避免直接操作真实连接 pthread_mutex_lock(&vhd->lock_ring); // 显式锁保护共享资源 ``` - 符合libwebsockets的无锁事件循环原则[^2] - 解决多线程并发访问问题(真wsi只能由服务线程操作) #### 3.2 资源消耗优化 - 单实例:整个服务周期只有一个假wsi实例 - 零网络开销:不产生实际网络流量 - 生命周期:随`lws_context`创建/销毁 #### 3.3 错误处理机制 ```c if (!vhd) // 检查虚拟主机数据有效性 break; ``` - 需显式验证关联数据(vhd)是否存在 - 无连接断开处理(因非真实连接) --- ### 4. 典型使用场景 #### 4.1 生产者-消费者模型 ```mermaid sequenceDiagram participant Worker as 工作线程 participant EventLoop as 事件循环 participant FakeWsi as 假wsi participant Clients as 客户端组 Worker->>EventLoop: lws_cancel_service() EventLoop->>FakeWsi: 触发CALLBACK FakeWsi->>Clients: 遍历标记可写 Clients->>EventLoop: WRITEABLE回调 ``` #### 4.2 定时任务触发 ```c // 定时器线程 void timer_thread() { while(running) { sleep(1); lws_cancel_service(context); // 每秒触发一次 } } ``` #### 4.3 外部事件集成 ```c // 第三方库回调 void external_event_handler() { lws_cancel_service(g_context); // 外部事件→libwebsockets } ``` --- ### 5. 注意事项 1. **禁止直接操作**:不能在假wsi上调用`lws_write()`等IO函数 2. **状态验证**:需检查`lws_get_vhost(wsi)`是否为NULL确认假wsi 3. **上下文关联**: ```c // 正确获取关联数据 struct per_vhost_data__minimal *vhd = (struct per_vhost_data__minimal *)lws_protocol_vh_priv_get( lws_get_vhost(wsi), lws_get_protocol(wsi)); ``` 4. **生命周期**:假wsi在`LWS_CALLBACK_PROTOCOL_INIT`时创建 --- ### 总结 假wsi机制是libwebsockets实现**线程安全事件通知**的核心设计: 1. 作为跨线程事件传递的安全载体 2. 提供全局上下文访问入口 3. 支持批量触发客户端操作 4. 避免直接操作真实连接的线程风险 这种设计在保证libwebsockets单线程事件循环模型的同时,扩展了多线程协作能力[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值