使用多线程优化硬盘上的读/写功能

时间:2016-09-27 19:21:04

标签: c multithreading winapi

我正在尝试阅读 - >加密/解密 - >逐个部门编写原始数据。我需要以某种方式优化时间,因为仅仅2GB的音量需要2个多小时(我的音量G:这里)。我尝试使用线程来处理时间问题,但没有显着的结果。该程序需要在日常使用的PC上运行。

每个线程在与其他线程不同的扇区块上运行。

  

我知道的事情:

     
      
  1. 写作时无法完成阅读(所以我处理了临界区问题)
  2.   
  3. 线程中的读/写由于寻道时间等原因而缩短了时间。
  4.   
  5. 由于延迟(由读/写磁头来回移动引起)导致太多线程可能无法完成任务。(给出错误DEVICE_NOT_READY))
  6.         

    我想问一下:

         
        
    1. 我是否可以同时利用线程在两个不同的扇区上进行读写或写入(因为我知道磁盘操作是使用已回答here的调度算法来执行的)?
    2.   
    3. 为什么程序在一个线程(在一个扇区上)写入时会产生错误,其他线程会尝试读取(在另一个扇区上)?
    4.   
    5. 您建议如何缩短时间?
    6.         

      代码:

DWORD WINAPI EncryptSectorBlock(LPVOID lpParam)
{
    PTARGS args = (PTARGS)lpParam;
    static unsigned char buffer[SECTOR_SIZE];

    printf("Thread No:%i start:%i  end:%i\n ", args->thread_id, args->sector_start, args->sector_end);

    for (int i = args->sector_start; i <= args->sector_end; i++)
    {
        //Entering critical section of the code. The Other Threads Would be first spin with 65536 loops and then set to
        // sleep until the worker threads releases the lock on critical section

        if (ReadSector(args->read, buffer, SECTOR_SIZE, i) != 1)
            printf("Thread: %i. Error reading sector %i\n",args->thread_id, i);
        else
            printf("Thread: %i. Read Sector %i Successfully\n", args->thread_id, i);

        xts_encrypt_sector(buffer, i, SECTOR_SIZE, &(args->ctx));

        //Critical Section starts
        EnterCriticalSection(&CriticalSection);
        if (WriteSector(args->write, buffer, SECTOR_SIZE, i) != 1)
            printf("Thread: %i. Error writing sector %i\n",args->thread_id ,i);
        else
            printf("Thread: %i. Wrote Sector %i Successfully\n", args->thread_id, i);
        //Critical Section Ends
        LeaveCriticalSection(&CriticalSection);


        //init to zero every time in case a sector is failed to be read or write, so it can recover from fault 
        //This may break in future.. Not proper mechanism to recover from   fault. just a hack.
         memset(buffer, 0, SECTOR_SIZE);
    }
    return 0;
  }

INT_RETURN EncryptFullVolume(wchar_t* volume, unsigned char* key)
{   
       //init variables here

            for (int i = 0; i < MAX_Threads; i++)
        {
            ArgsDataArray[i] = (PTARGS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TARGS));

            if (ArgsDataArray[i] == NULL)
            {
                // If the array allocation fails, the system is out of memory
                // so there is no point in trying to print an error message.
                // Just terminate execution.
                ret = EXIT_FAILURE;
            }
            else
            {
                // Generate unique data for each thread to work with here

               // Create the thread to begin execution on its own.
                hThreadArray[i] = CreateThread(
                    NULL,                   // default security attributes
                    0,                      // use default stack size  
                    EncryptSectorBlock,     // thread function name
                    ArgsDataArray[i],          // argument to thread function 
                    0,                      // use default creation flags 
                    &ThreadIdArray[i]);   // returns the thread identifier 

                if (hThreadArray[i] == NULL)
                {
                    ret = EXIT_FAILURE;
                }

                sector_offset += sectors_per_thread;
            }

        } // End of main thread creation loop.

            // Wait until all threads have terminated.

        DWORD result = WaitForMultipleObjects(MAX_Threads, hThreadArray, TRUE, INFINITE);


        // Free all the dynamically allocated structures
    }
    }
   return ret;

}

1 个答案:

答案 0 :(得分:4)

你的观点2并非如此。

对于常规磁盘,最佳访问模式是大顺序读取,而不必由于多个线程争用磁盘时间而来回跳过(使其在搜索中浪费时间);此外,顺序读取与操作系统和磁盘本身完成的预读缓存相得益彰。

您可能希望多线程只是处理您从磁盘读取的数据,但鉴于在现代PC上您的处理器比这个任务的磁盘更快,您的任务将是IO绑定。如果我是你,我只需要一个线程在大块中执行异步顺序IO(一次考虑4 MB数据),在等待磁盘执行其操作时加密数据。另一种可能性是使用两个线程(一个执行IO,一个加密)和同步IO执行基本相同的操作。