最近测试提了一个Bug,原来一直正常的服务进程在新的系统中无法正常工作,现象就是显卡GPU没有正常工作。
这两天跟踪了一下问题,找到了原因,这里把具体的解决办法贴出来,方便有同样问题的朋友快速解决问题^_^。
原因分析:
Vista之后,操作系统引入了Session 0 Isolation的机制,将系统服务全部隔离到会话0中执行,但是会话0中的系统服务无法使用显卡设备,导致cuda在加载显卡驱动时失败,而无法启动GPU进行并行计算。
具体的会话0隔离机制可以参考MSDN文章:
http://msdn.microsoft.com/en-us/library/bb756986.aspx
解决方案:
找到了原因一切就好办了,从分析来看,主要是会话0中无法加载显卡驱动,所以这里需要将使用显卡的进程越狱到用户会话中,比如会话1等。
这个办法在CUDA的论坛中已经有过讨论了,这里有兄台给出了一些示例代码,可以参考:
http://forums.nvidia.com/index.php?showtopic=93450
这里说说我的具体解决方案:
- 在服务进程中,循环枚举可用用户会话ID
- 获取有效用户会话之后,获取对应用户的会话令牌
- 以该用户会话启动新的进程
涉及到的API如下:
通过WTSEnumerateSessions 获取所有有效会话,通过判断WTS_SESSION_INFO的State字段,获取活动会话ID
记得使用完之后,通过WTSFreeMemory释放相关内存
通过WTSQueryUserToken获取会话ID对应的会话Token
最后调用CreateProcessAsUser将进程启动到用户会话中,就可以了
总结:
其实上面的方法,相当于是延时启动,当有用户登陆之后,才启动真正的工作进程。
上述方案,需要对工程进行进程分离,将实际工作的进程独立起来,以启动到用户会话中。
有一个小问题,目前没有找到相关解决方案,有待进一步学习,有知道的朋友请分享一下^_^:
当开启UAC功能时,通过CreateProcessAsUser启动的进程无法获取管理员权限,如果工作进程需要管理员权限,可能需要关闭UAC功能才行。