在程序中使用线程读写文件,当线程中读写文件的时间比较长时,程序主界面的操作明显感觉迟缓,这说明线程在读写文件时占用了主程序的大部分CPU时间,但是如果让读写文件的这个工作交给子进程来操作,则子进程读写文件时对主程序的界面进行操作仍然非常顺滑流畅,不会出现使用线程的那种迟缓的情况。这是不是说线程实际上并非真正的多任务?

解决方案 »

  1.   

    我倒是希望不是正确的,用线程总比用进程来的省心啊。但是经过多次测试让我很失望,线程比OnTime好不到哪。
      

  2.   

    线程在读写文件时占用了主程序的大部分CPU时间?
    线程调度是OS的事、、、
      

  3.   

    所以我问你你上面的实验的结果是不是一定保证正确啊!
    就我所知,OS调度对象是线程而不是进程,所以如果你的工作占用CPU的话,那么不管是多线程还是用另一个进程,效果应该是一样的。 
      

  4.   

    windows下子进程 资源 什么的不是应该独立的么,对主程序的界面能有什么影响?
    有误楼下斧正
      

  5.   

    http://www.cnblogs.com/Fly-pig/archive/2011/01/19/1939607.html---------------------
    跟你说有些事情会阻塞整个系统的,你就是做成子进程都不管用。
      

  6.   

    俺的意思是说,您这个读写文件的例子,恰好是系统的一项最核心功能,文件读写会拖累整个系统。如果子线程中只是执行一些WaitForSingleObject之类不拖累整个系统的操作,那子进程与子线程就没差别了。
      

  7.   

    开启子线程, 默认子线程的优先级别, 跟主线程的优先级别是一至的, 即CPU平均分配处理时间(特别是你的机器为单核时) 多核时, 代表的是其中一个CPU不停的读写硬盘, 但读写硬盘是会拖慢整个系统的.开启进程, 你简单写个示例代码, 两个进程死循环, 然后打印1s种有多少次循环做了. 然后你可以占击激活某一个进程, 你就会发现, 被激活的进程, 会获得更多的CPU处理时间的. 即开启两个进程, 它们之间不是平等分配CPU的, 而是被激活的进程会有较高的CPU使用优先权.
      

  8.   


    个人认为线程的优先级只是这样一个状态:
    同进程中的线程优先级只能在代码行之间切换,如果低优先级线程是正在执行诸如调用API函数或者正在读写硬盘等等那些需要等待执行结束才能返回继续执行下一行代码的情形,那么高优先级线程同样必须等待,直到低优先级线程要运行下一行代码时才能继续。
      

  9.   

    也就是说系统不能在低优先级线程调用API函数未返回前或单个磁盘操作未完成前将控制权分给高优先级线程。
      

  10.   

    "在低优先级线程调用API函数未返回前或单个磁盘操作未完成前将控制权分给高优先级线程"涉及到优先度颠覆的状况,由系统决策,并不是一成不变的。
      

  11.   

    lz还是参考下《windows 核心编程》把概念弄清楚
      

  12.   


    我不知道会不会把控制权交给优先级高的线程, 但起码, 优先级不一样的话, 也就代表优先级低的线程, 进行全系统影响的操作的次数, 也会相应减少. 结果就是你感觉不卡了. 不要把单次的影响系统性能的操作作为大局, 影响你的程序卡还是不卡的, 是这类操作作被连续运行了多少次. 
    断断续续的运行, 每次运行最多只会使用1ms的时间, 对你的界面肯定不影响啦, 但使用时间是1ms, 然后同等优先级, 即两个线程各只有500ms用, 界面不卡才怪
      

  13.   


    线程的优先级只能在代码行间切换,即优先级高的线程可能运行几行代码后低优先级线程才能运行一行代码,最低优先级的线程甚至可能必须等待高优先级线程运行结束后才有机会执行,这种线程切换运行很可能只能在代码行之间执行,如果某个线程正在运行的某个API函数未完成或某个磁盘操作未完成,那在此期间其它线程将没机会继续运行,不管它们的优先级为何。
      

  14.   

    你把源代码发到我邮箱里面
    [email protected]
      

  15.   

    线程切换运行很可能只能在代码行之间.
    我认为是在机器指令间,这就是为什么线程切换的上下文(context)包含CPU的全部寄存器。
      

  16.   

    计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令.所谓多线程的并发运行,其实是指从宏观上看,各个线程轮流获得CPU的使用权,分别执行各自的任务.因此,你这样的耗时测试没意思,只能表明你的CPU是单核,so on
      

  17.   

    Windows在进行某些任务时,比如I/O、音频等操作时会临时提升线程的优先权的。
      

  18.   

    你始终不把你的代码放出来,反正这个程序在我这里没有出现卡的现象#include<windows.h>
    #include<string.h>
    #include<CommCtrl.h>
    static volatile int stop=0,cc;
    DWORD WINAPI ThreadProc(LPVOID lpParameter)
    {
    void*buffer=GetModuleHandleW(L"kernel32.dll");DWORD c;
    HANDLE hFile=CreateFileW(L"D:\\Downloads\\a.dat",GENERIC_WRITE,FILE_SHARE_READ,0,CREATE_ALWAYS,FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH,0);
    while(stop==0)
    {
    WriteFile(hFile,buffer,512*16,&c,0);
    }
    CloseHandle(hFile);
    return 0;
    }
    DWORD WINAPI ThreadProc2(LPVOID lpParameter)
    {
    while(stop==0)
    {
    ++cc;
    }
    return 0;
    }
    LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
    {
    switch(uMsg)
    {
    case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case 0:
    stop=0;
    CloseHandle(CreateThread(0,0,ThreadProc,0,0,0));
    CloseHandle(CreateThread(0,0,ThreadProc2,0,0,0));
    break;
    case 1:
    stop=1;
    break;
    }
    return 0;
    case WM_DESTROY:
    PostQuitMessage(0);
    return 0;
    case WM_CLOSE:DestroyWindow(hwnd);
    case WM_CREATE:return 0;
    default: return DefWindowProcW(hwnd,uMsg,wParam,lParam);
    }
    }BOOL InsertListViewItems(HWND hWndListView, int cItems)
    {
        LVITEM lvI;wchar_t s[]=L"sdfsodfno";    // Initialize LVITEM members that are common to all items.
        lvI.pszText   = s; 
        lvI.mask      = LVIF_TEXT | LVIF_IMAGE |LVIF_STATE;
        lvI.stateMask = 0;
        lvI.iSubItem  = 0;
        lvI.state     = 0;    // Initialize LVITEM members that are different for each item.
        for (int index = 0; index < cItems; index++)
        {
            lvI.iItem  = index;
            lvI.iImage = index;
    (*(long*)lvI.pszText)+=1;
    (*(long*)(lvI.pszText+2))+=1;
            // Insert items into the list.
            if (ListView_InsertItem(hWndListView, &lvI) == -1)
                return FALSE;
        }    return TRUE;
    }
    void Entry(void)
    {
    static WNDCLASSEXW WindowClass={sizeof(WNDCLASSEXW),0,WindowProc,0,0,(HINSTANCE)0x400000,0,0,0,0,L"wc",0};ATOM ClassAtom;HWND hwnd,lv;MSG msg;LVCOLUMN lvc;
    ClassAtom=RegisterClassExW(&WindowClass);
    hwnd=CreateWindowExW(0,(LPWSTR)(unsigned long)ClassAtom,0,WS_OVERLAPPEDWINDOW,0,0,600,600,0,0,0,0);
    CreateWindowExW(0,L"Button",L"start",WS_VISIBLE|WS_CHILD,10,10,50,50,hwnd,(HMENU)0,0,0);
    CreateWindowExW(0,L"Button",L"end",WS_VISIBLE|WS_CHILD,60,10,50,50,hwnd,(HMENU)1,0,0);
    lv=CreateWindowExW(0,WC_LISTVIEWW,L"",WS_CHILD | LVS_REPORT | LVS_EDITLABELS|WS_VISIBLE|WS_BORDER,100, 100,400,400,hwnd,(HMENU)3,0,NULL); 
    lvc.mask =  LVCF_WIDTH | LVCF_TEXT;
    lvc.pszText = L"ssss";
        lvc.cx = 100; 
    ListView_InsertColumn(lv, 0, &lvc);
    InsertListViewItems(lv,400);
    UpdateWindow(hwnd);
    ShowWindow(hwnd,1);
    while(GetMessageW(&msg,0,0,0))DispatchMessageW(&msg);
    ExitProcess(0);
    }
      

  19.   


    SetThreadAffinityMask(); 
    SetThreadIdealProcessor(); 上面两个都用过,没效。
      

  20.   

    your cpu is solo core? support numa?
      

  21.   

    线程在做循环IO操作时,需要手动释放时间片,不然会一直占用CPU。现在很多程序的线程都影响到整个IO了~
      

  22.   

    我测试了下列宁的代码,使用的数据量为562547KB(549M),发现,这个和机器有关,小型工作站上没有任何延迟现象。自己的本本上有这个现象,若在线程中加sleep则情况较好。
    PS:我本本是单核的,不知道是否验证了我28L的想法。
      

  23.   

    如果是单cpu,多线程肯定是伪多任务的,曾经出现过拷贝大文件时,整个系统假死的情况
      

  24.   

    把CloseHandle(CreateThread(0,0,ThreadProc2,0,0,0));去掉,我想单核也不会卡
    复制大文件卡多半是因为缓存把内存撑爆了。
    一个线程等待io时将时间分给其他线程,这是多任务操作系统必备的功能
      

  25.   

    不管单核或双核,测试的结果主程序用线程或用子进程的线程效果差别很大,特别是当线程的循环中单行代码(调用API或者IO操作)的任务量需要耗费100毫秒以上才完成时,如果使用主程序的线程方式,在线程运行时你将会明显的感觉主程序的界面操作非常的迟缓(卡),而如果使用主程序的子进程的线程方式,在子进程的线程运行时你对主程序的界面操作依然很流畅。 反应迟缓和内存或缓存占用没有关系,因为迟缓的现象并没有随着长时间不断的操作而加重。各位说了这么多,你们为什么不测试下:A.主程序的线程中弄个循环的IO操作,让IO操作耗时在100毫秒(当然耗时越长感觉将会越明显)以上,运行线程,操作主界面;B.主程序的子进程的线程中同样弄个循环的IO操作,让IO操作耗时在100毫秒以上,运行线程,操作主界面。比较两者之间的差别你们就会清楚,同一程序中的线程运行切换实际是在代码行间而不是CPU指令间。
      

  26.   


    请教如何释放?难道是用Sleep?
      

  27.   

    手动释放时间片用SwitchToThread,Sleep,WaitForSingleObject等
    线程等待io时就会把时间让出给其他线程,在线程调度上干的事和Sleep没多大区别,我把一次WriteFile的数据量提高到很大也没出现你的卡现象
    而且c语言编译成的是机器码,不存在代码行间这个概念,cpu认的是指令,而不是一行行代码
      

  28.   


    Sleep是没用的,因为你在API中不可能使用它,在单个磁盘读写也不可能用到。你的WriteFile是放在循环中的吗,或者你操作界面时WriteFile还在运行吗,还有你最好在界面上有滚动条控件,然后你拖拉滚动条看看拖拉过程中滚动条是否有停滞现象。
      

  29.   

    程序中直接用线程和用子进程的线程肯定是有差别的。目前有很多软件都是用的子进程方式,例如谷歌浏览器:每个页面都是独立的进程;windows 的缩略图浏览窗口也是:打开任务管理器,并用windows文件浏览窗口浏览某个有多个图片文件的文件夹,一旦出现未创建缩略图的图片文件的图标时任务管理器中将出现进程DLLHOST,DLLHOST应该就是用来创建缩略图的用途之一,因为DLLHOST出现后文件夹中的图片文件的图标便一个个变为图片缩略图,而这个时候你拖拉窗口上的滚动条会发现滚动条的滚动依然很流畅。如果你用过ISEE应该就明白,缩略图的创建也是比较耗费时间的,ISEE在滚动时就非常卡,还有电驴等等没有使用子进程方式的多任务软件界面滚动都比较卡。windows 的缩略图浏览窗口为什么会用子进程DLLHOST来创建缩略图而不用线程,这就很能说明问题啊。
      

  30.   

    谷歌浏览器用多进程主要是为了安全和防止一崩全崩,而且负责显示界面的进程只有一个,其他的是后台渲染
    你运行chrome.exe --single-process单进程模式看卡不卡explorer用dllhost不能说明什么问题,资源管理器除了缩略图还干很多事情
    你用资源管理器进行全盘搜索,格式化磁盘时都是一个进程,也不卡isee我没用过,但是电驴我这里并不卡,迅雷还是单进程的时候也不怎么卡,3dsmax有时是比较卡,但不是由于io密集
      

  31.   

    你把WriteFile这样的api看成整体了,不是调用一次WriteFile就是一次性不分块写入
    从直觉上来看WriteFile的实现应该是分块的,因为文件可能散布在硬盘上,因此肯定要分块写你可以去看一下fastfat.sys的源代码里面的FatMultipleAsync的实现,它就是在一个循环中,完成对每个run的io
    对于fat文件系统WriteFile对有多个run的文件最终会用到这个函数
      

  32.   

    确实,用WriteFile不是很卡,但仍然可以感觉到卡。如果你在线程中用GIDPLUS将很多图片放大一倍再另存成图片文件,这会让你明显感到很卡。
      

  33.   

    线程中用GIDPLUS将很多图片放大一倍再另存成图片文件
    这个卡不奇怪,因为放大图片是cpu密集型,这个操作会导致界面卡,而保存文件并不是导致卡的关键原因
      

  34.   


    绝对不是,当界面需要刷新的东西比较多时卡会更为明显。 你说放大图片是cpu密集型,这个卡不奇怪,但是同样的代码我放在子进程的线程中一点不卡,而放在主程序的线程中明显卡的厉害。
      

  35.   


    都有测试过啊,都一样。你可以以大约如下的代码放在线程中测试下看看:
    for(int i = 0; i < iCount; i++)
    {
    Image srcBmp(imageFileNames[i]);
    Bitmap newBmp(srcBmp.GetWidth()*2, srcBmp.GetHeight()*2);
    Graphics grnewBmp(&newBmp);
    grnewBmp.DrawImage(&srcBmp, 0,0, srcBmp.GetWidth()*2, srcBmp.GetHeight()*2);
    newBmp.Save(...);
    }
      

  36.   

    无论多进程还是多线程,只要还是单CPU,那都可以说是“伪多任务”,因为这些进程或线程都必须由内核来调度获取/释放CPU时间片,延迟是不可避免的。
      

  37.   

    这个分析其实还要设计到很多的结构,感觉XP 在SP3后面的变动是最大的  不管是内存机制还是核心分配机制   变动的非常大    也许OS为了满足多核CPU的能力,从来对OS进程进行了统一的算法或时间片刻分配  对于线程的CPU片刻是归结在进城之下    也就是说  如果一个进城只分配了那么久的CPU片刻   那么如果当线程高负荷运行的情况下   进城主线程可能无法或获取降低CPU片刻。而采用子进程的方式却不影响,这也是为多任务处理的一个调整点,现在都是多核的电脑了,所以多核电脑对于SP3没有什么差异的感觉,而单核或超线程电脑对内存管理机制和CPU控制机制,都异常变慢。  这归结到OS的原因吧!