Aracılığıyla paylaş


Bekleyen G/Ç İşlemlerini İptal Etme

Kullanıcıların yavaş veya engellenen G/Ç isteklerini iptal etmelerine izin vermek uygulamanızın kullanılabilirliğini ve sağlamlığını artırabilir. Örneğin, çok yavaş bir cihaza yapılan OpenFile işlevine ait bir çağrı engellenirse, bu çağrının iptali uygulamayı sonlandırmadan, yeni parametrelerle çağrıyı yeniden yapmayı sağlar.

Windows Vista, iptal özelliklerini genişletir ve zaman uyumlu işlemleri iptal etme desteği içerir.

Not

CancelIoEx işlevinin çağrılması G/Ç işleminin iptal edileceğini garanti etmez; işlemi işleyen sürücünün iptali desteklemesi ve işlemin iptal edilebilecek bir durumda olması gerekir.

İptal Konuları

İptal çağrılarını programlama sırasında aşağıdaki noktaları göz önünde bulundurun:

  • Alt sürücülerin iptali doğru şekilde desteklediğinin garantisi yoktur.
  • Asenkron G/Ç iptal edilirken, CancelIoEx fonksiyonuna bir örtüşen yapı sağlanmadığında, fonksiyon, süreçteki tüm iş parçacıklarında dosya üzerindeki tüm bekleyen G/Ç'yi iptal etmeye çalışır. Her iş parçacığı ayrı ayrı işlenir, bu nedenle bir iş parçacığı işlendikten sonra diğer tüm iş parçacıklarının dosya için G/Ç'leri iptal edilmeden önce dosyada başka bir G/Ç başlatılabilir ve bu da eşitleme sorunlarına neden olur.
  • Asenkron G/Ç'yi iptal ederken, hedeflenen iptalde örtüşen yapıları yeniden kullanmayın. G/Ç işlemi tamamlandıktan sonra (başarılı veya iptal edilmiş durumda) çakışan yapı artık sistem tarafından kullanımda değildir ve yeniden kullanılabilir.
  • Eşzamanlı G/Ç iptal edilirken, CancelSynchronousIo işlevi çağrıldığında iş parçacığındaki mevcut eşzamanlı çağrının iptal edilmeye çalışıldığı görülür. Çağrıların eşitlenmesinin doğru olduğundan emin olmanız gerekir; bir dizi aramada yanlış arama iptal edilebiliyordu. Örneğin, CancelSynchronousIo işlevi, zaman uyumlu bir işlem olan operasyon X için çağrılırsa, Y işlemi yalnızca operasyon X tamamlandıktan sonra başlar (normalde veya bir hatayla). X işlemini çağıran iş parçacığı daha sonra X'e başka bir zaman uyumlu çağrı başlatırsa, iptal çağrısı bu yeni G/Ç isteğini kesintiye uğratabilir.
  • Senkron G/Ç'yi iptal ederken, bir iş parçacığı uygulamanın farklı bölümleri arasında paylaşıldığında (örneğin, bir iş parçacığı havuzundaki iş parçacığı ile) bir yarış koşulunun mevcut olabileceğini unutmayın.

İptal Edilemeyen İşlemler

Bazı işlevler CancelIo, CancelIoExveya CancelSynchronousIo işlevi kullanılarak iptal edilemez. Bu işlevlerden bazıları iptale izin verecek şekilde genişletilmiştir (örneğin, CopyFileEx işlevi) ve bunun yerine bunları kullanmanız gerekir. İptali desteklemeye ek olarak, bu işlevler işlemin ilerleme durumunu takip ederken sizi destekleyecek yerleşik geri çağırmalara da sahiptir. Aşağıdaki işlevler iptali desteklemez:

Daha fazla bilgi için bkz. G/Ç Tamamlama/İptal Yönergeleri.

Asenkron G/Ç İptal Ediliyor

G/Ç işlemini veren işlemdeki herhangi bir iş parçacığından zaman uyumsuz G/Ç'yi iptal edebilirsiniz. G/Ç'nin yapıldığı tanıtıcıyı ve isteğe bağlı olarak G/Ç'yi gerçekleştirmek için kullanılan çakışmalı yapıyı belirtmeniz gerekir. çakışan yapıda veya tamamlama geri çağırmasında döndürülen durumu inceleyerek iptalin gerçekleşip gerçekleşmediğini belirleyebilirsiniz. ERROR_OPERATION_ABORTED durumu işlemin iptal edildiğine işaret eder.

Aşağıdaki örnek, bir zaman aşımı alıp bir okuma işlemi yapmayı deneyen ve zaman aşımı süresi dolarsa CancelIoEx işleviyle onu iptal eden bir yordamı göstermektedir.

#include <windows.h>

BOOL DoCancelableRead(HANDLE hFile,
                 LPVOID lpBuffer,
                 DWORD nNumberOfBytesToRead,
                 LPDWORD lpNumberOfBytesRead,
                 LPOVERLAPPED lpOverlapped,
                 DWORD dwTimeout,
                 LPBOOL pbCancelCalled)
//
// Parameters:
//
//      hFile - An open handle to a readable file or device.
//
//      lpBuffer - A pointer to the buffer to store the data being read.
//
//      nNumberOfBytesToRead - The number of bytes to read from the file or 
//          device. Must be less than or equal to the actual size of
//          the buffer referenced by lpBuffer.
//
//      lpNumberOfBytesRead - A pointer to a DWORD to receive the number 
//          of bytes read after all I/O is complete or canceled.
//
//      lpOverlapped - A pointer to a preconfigured OVERLAPPED structure that
//          has a valid hEvent.
//          If the caller does not properly initialize this structure, this
//          routine will fail.
//
//      dwTimeout - The desired time-out, in milliseconds, for the I/O read.
//          After this time expires, the I/O is canceled.
// 
//      pbCancelCalled - A pointer to a Boolean to notify the caller if this
//          routine attempted to perform an I/O cancel.
//
// Return Value:
//
//      TRUE on success, FALSE on failure.
//
{
    BOOL result;
    DWORD waitTimer;
    BOOL bIoComplete = FALSE;
    const DWORD PollInterval = 100; // milliseconds

    // Initialize "out" parameters
    *pbCancelCalled = FALSE;
    *lpNumberOfBytesRead = 0;

    // Perform the I/O, in this case a read operation.
    result = ReadFile(hFile,
                  lpBuffer,
                  nNumberOfBytesToRead,
                  lpNumberOfBytesRead,
                  lpOverlapped );

    if (result == FALSE) 
    {
        if (GetLastError() != ERROR_IO_PENDING) 
        {
            // The function call failed. ToDo: Error logging and recovery.
            return FALSE; 
        }
    } 
    else 
    {
        // The I/O completed, done.
        return TRUE;
    }
        
    // The I/O is pending, so wait and see if the call times out.
    // If so, cancel the I/O using the CancelIoEx function.

    for (waitTimer = 0; waitTimer < dwTimeout; waitTimer += PollInterval)
    {
        result = GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesRead, FALSE );
        if (result == FALSE)
        {
            if (GetLastError() != ERROR_IO_PENDING)
            {
                // The function call failed. ToDo: Error logging and recovery.
                return FALSE;
            }
            Sleep(PollInterval);
        }
        else
        {
            bIoComplete = TRUE;
            break;
        }
    }

    if (bIoComplete == FALSE) 
    {
        result = CancelIoEx( hFile, lpOverlapped );
        
        *pbCancelCalled = TRUE;

        if (result == TRUE || GetLastError() != ERROR_NOT_FOUND) 
        {
            // Wait for the I/O subsystem to acknowledge our cancellation.
            // Depending on the timing of the calls, the I/O might complete with a
            // cancellation status, or it might complete normally (if the ReadFile was
            // in the process of completing at the time CancelIoEx was called, or if
            // the device does not support cancellation).
            // This call specifies TRUE for the bWait parameter, which will block
            // until the I/O either completes or is canceled, thus resuming execution, 
            // provided the underlying device driver and associated hardware are functioning 
            // properly. If there is a problem with the driver it is better to stop 
            // responding here than to try to continue while masking the problem.

            result = GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesRead, TRUE );

            // ToDo: check result and log errors. 
        }
    }

    return result;
}

Eşzamanlı G/Ç İptali

G/Ç işlemini başlatan süreçteki herhangi bir iş parçacığından zaman uyumlu G/Ç'yi iptal edebilirsiniz. Şu anda G/Ç işlemini gerçekleştiren iş parçacığının tanıtıcısını belirtmeniz gerekir.

Aşağıdaki örnekte iki rutin gösterilmektedir:

  • SynchronousIoWorker işlevi, CreateFile işlevine yapılan bir çağrıyla başlayan, zaman uyumlu dosya G/Ç işlemlerini uygulayan bir çalışan iş parçacığıdır. Eğer rutin başarılı olursa, buraya dahil edilmeyen ek işlemler de yapılabilir. gCompletionStatus genel değişkeni, tüm işlemlerin başarılı olup olmadığını veya bir işlemin başarısız olup olmadığını veya iptal edilip edilmediğini belirlemek için kullanılabilir. Genel değişken dwOperationInProgress, dosya G/Ç'nin devam edip etmediğini gösterir.

    Not

    Bu örnekte kullanıcı arabirimi iş parçacığı, çalışan iş parçacığının varlığını da denetleyebiliyor.

    Buraya dahil edilmeyen ek manuel denetimler, SynchronousIoWorker işlevinde gereklidir. Bu denetimler, dosya G/Ç çağrıları arasındaki belirli periodlarda iptal talep edilirse, geri kalan işlemlerin iptal edileceğinden emin olunmasını sağlar.

  • MainUIThreadMessageHandler işlevi, kullanıcı arabirimi iş parçacığının pencere yordamı içinde ileti işleyicisinin benzetimini yapar. Kullanıcı, kullanıcı tanımlı bir pencere iletisi oluşturan bir denetime (WM_MYSYNCOPStarafından işaretlenen bölümde) tıklayarak zaman uyumlu dosya işlemleri kümesi ister. Bu, CreateFileThread işlevini kullanarak yeni bir iş parçacığı oluşturur ve ardından SynchronousIoWorker işlevini başlatır. Çalışan iş parçacığı, istenen G/Ç işlemlerini gerçekleştirirken, Kullanıcı Arabirimi iş parçacığı iletileri işlemeye devam eder. Kullanıcı tamamlanmamış işlemleri iptal etmeye karar verirse (genellikle bir iptal düğmesine tıklayarak), yordam (WM_MYCANCELtarafından işaretlenen bölümde), CreateFileThread işlevi tarafından döndürülen iş parçacığı tanıtıcısını kullanarak CancelSynchronousIo işlevini çağırır. CancelSynchronousIo işlevi, iptal girişiminden hemen sonra sonuç verir. Son olarak, kullanıcı veya uygulama daha sonra dosya işlemlerinin tamamlanıp tamamlanmadığına bağlı olan başka bir işlem isteyebilir. Bu durumda, yordam (WM_PROCESSDATAtarafından işaretlenen bölümde) önce işlemlerin tamamlandığını doğrular ve ardından temizleme işlemlerini yürütür.

    Not

    Bu örnekte, iptal işlemi işlem sırasında herhangi bir yerde gerçekleşebileceğinden, devam etmeden önce çağıranın durumun tutarlı veya en azından anlaşılır olduğundan emin olması gerekebilir.

// User-defined codes for the message-pump, which is outside the scope 
// of this sample. Windows messaging and message pumps are well-documented
// elsewhere.
#define WM_MYSYNCOPS    1
#define WM_MYCANCEL     2
#define WM_PROCESSDATA  3

VOID SynchronousIoWorker( VOID *pv )
{
    LPCSTR lpFileName = (LPCSTR)pv;
    HANDLE hFile;
    g_dwOperationInProgress = TRUE;    
    g_CompletionStatus = ERROR_SUCCESS;
     
    hFile = CreateFileA(lpFileName,
                        GENERIC_READ,
                        0,
                        NULL,
                        OPEN_EXISTING,
                        0,
                        NULL);


    if (hFile != INVALID_HANDLE_VALUE) 
    {
        BOOL result = TRUE;
        // TODO: CreateFile succeeded. 
        // Insert your code to make more synchronous calls with hFile.
        // The result variable is assumed to act as the error flag here,
        // but can be whatever your code needs.
        
        if (result == FALSE) 
        {
            // An operation failed or was canceled. If it was canceled,
            // GetLastError() returns ERROR_OPERATION_ABORTED.

            g_CompletionStatus = GetLastError();            
        }
             
        CloseHandle(hFile);
    } 
    else 
    {
        // CreateFile failed or was canceled. If it was canceled,
        // GetLastError() returns ERROR_OPERATION_ABORTED.
        g_CompletionStatus = GetLastError();
    }

    g_dwOperationInProgress = FALSE;
}  

LRESULT
CALLBACK
MainUIThreadMessageHandler(HWND hwnd,
                           UINT uMsg,
                           WPARAM wParam,
                           LPARAM lParam)
{
    UNREFERENCED_PARAMETER(hwnd);
    UNREFERENCED_PARAMETER(wParam);
    UNREFERENCED_PARAMETER(lParam);
    HANDLE syncThread = INVALID_HANDLE_VALUE;

    //  Insert your initializations here.

    switch (uMsg) 
    {
        // User requested an operation on a file.  Insert your code to 
        // retrieve filename from parameters.
        case WM_MYSYNCOPS:    
            syncThread = CreateThread(
                          NULL,
                          0,
                          (LPTHREAD_START_ROUTINE)SynchronousIoWorker,
                          &g_lpFileName,
                          0,
                          NULL);

            if (syncThread == INVALID_HANDLE_VALUE) 
            {
                // Insert your code to handle the failure.
            }
        break;
    
        // User clicked a cancel button.
        case WM_MYCANCEL:
            if (syncThread != INVALID_HANDLE_VALUE) 
            {
                CancelSynchronousIo(syncThread);
            }
        break;

        // User requested other operations.
        case WM_PROCESSDATA:
            if (!g_dwOperationInProgress) 
            {
                if (g_CompletionStatus == ERROR_OPERATION_ABORTED) 
                {
                    // Insert your cleanup code here.
                } 
                else
                {
                    // Insert code to handle other cases.
                }
            }
        break;
    } 

    return TRUE;
} 

Eşzamanlı ve Eşzamansız G/Ç