NtSetInformationProcess设置硬盘ProcessIoPriority

机械硬盘是目前大多机器的瓶颈。固态硬盘价格依然较贵,而且寿命太短,不适合长期高负荷写入。机械硬盘的问题在于,默认是按照最大速度写入,当连续写入错误达到一定值时,会造成降速,磁盘模式由UDMA6降低为UDMA2或PIO,windows操作系统不能有效的识别何时应该降速运转,以避免错误达到减速模式阈值,在变成降速模式后又很难恢复成UDMA6。另一问题是,当机械硬盘按默认最大速度写入时,会造成系统的其他资源不可用,表现为用户界面上很卡,相信很多人都有类似的体验,当复制大文件时,系统什么也干不了,做什么都一顿一顿的。

 

经查,process lasso、IOPriority是解决界面卡顿的工具,反编译IOPriority可以发现使用的是NtSetInformationProcess这个微软未公布的API。由于没有文档,我在pinvoke调用它时费了不少时间。幸好它的get版本是有公布的

NTSTATUS WINAPI NtQueryInformationProcess(
  _In_       HANDLE ProcessHandle,
  _In_       PROCESSINFOCLASS ProcessInformationClass,
  _Out_      PVOID ProcessInformation,
  _In_       ULONG ProcessInformationLength,
  _Out_opt_  PULONG ReturnLength
);

[DllImport("ntdll.dll", SetLastError = true)]
public static extern int NtQueryInformationProcess(IntPtr processHandle, PROCESS_INFORMATION_CLASS processInformationClass,ref IntPtr processInformation, uint processInformationLength, out uint returnLength);

经过调用,没问题,ref IntPtr processInformation返回了进程的IO优先级。但是NtSetInformationProcess的这个参数却不能简单的使用IntPtr。先后遇到了

STATUS_DATATYPE_MISALIGNMENT 0x80000002 //An unaligned data reference was encountered.

STATUS_ACCESS_VIOLATION   0xC0000005 //A memory access violation occurred.  

STATUS_INVALID_PARAMETER 0xC000000D //参数无效

这个参数传入指针,unsafe编译是可以正确返回的。

//private static unsafe void setIOPrio(IntPtr hProcess, int newPrio)
        //{
        //    int* ptr = &newPrio;
        //    int result = Win32.NtSetInformationProcess(hProcess, PROCESS_INFORMATION_CLASS.ProcessIoPriority, ptr, 4);
        //    Console.WriteLine(result.ToString("x2"));
        //    ptr = null;
        //}

查找0xC0000005,下面这篇文章给了我启发

http://windows-tech.info/1/3f3692ead908c170.php

My guess would be that with your pinning, it is not long enough. If the unmanaged code is asynchronous, then you can not be sure when to unpin the mRect object. Using this assumption, your mRect needs to be static, pinned at the start of the problem and then unpinned at the end of the program, otherwise your mRect object can be moved, the unmanaged code is likely writing to the address it had from before (writing over another object with invalid data) then your managed code is trying to access the now corrupt memory and causing access violation. It's not so much the unmanaged code finding the object, but having the assumption that the object hasn't been moved, so it is free to write to that area and corrupt the data.

I had a similar thing happen to me with asynchronous P/Invoke calls and repeating them.

Get方法恩能够成功,而Set不行,可能是因为get是同步的,而set是异步的,当真正执行时,这个传入的指针可能已经被GC回收或移位了。最终用Marshal做成功。

 private static void setIOPrio(IntPtr hProcess, int newPrio)
        {
            byte[] src = new byte[4];
            src[0] = (byte) newPrio;//only 0 1 2 can be set on my win8
            IntPtr hglobal = Marshal.AllocHGlobal(new IntPtr(4));
            Marshal.Copy(src, 0, hglobal, 4);
            int result = Win32.NtSetInformationProcess(hProcess, PROCESS_INFORMATION_CLASS.ProcessIoPriority, hglobal, 4u);
            Marshal.FreeHGlobal(hglobal);

            Console.WriteLine(result.ToString("x2"));
        }

在win8中,IO优先级只有0,1,2,默认2 normal,但只有设为 0 very low才能看到硬盘不是最大速度写入,系统不会卡顿。

 

http://files.cnblogs.com/devourer/IOPriorityIOConsumer.7z

转载于:https://www.cnblogs.com/devourer/p/3228416.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值