비동기 메서드 호출

Media Foundation에서는 많은 작업이 비동기적으로 수행됩니다. 비동기 작업은 호출 스레드를 차단하지 않으므로 성능을 향상시킬 수 있습니다. Media Foundation의 비동기 작업은 명명 규칙 Begin...End....를 사용하는 메서드 쌍으로 정의됩니다. 이러한 두 메서드는 함께 스트림에서 비동기 읽기 작업을 정의합니다.

비동기 작업을 시작하려면 Begin 메서드를 호출합니다. Begin 메서드는 항상 두 개 이상의 매개 변수를 포함합니다.

  • IMFAsyncCallback 인터페이스에 대한 포인터입니다. 애플리케이션은 이 인터페이스를 구현해야 합니다.
  • 선택적 상태 개체에 대한 포인터입니다.

IMFAsyncCallback 인터페이스는 작업이 완료되면 애플리케이션에 알립니다. 이 인터페이스를 구현하는 방법에 대한 예제는 비동기 콜백 구현을 참조하세요. 상태 개체는 선택 사항입니다. 지정된 경우 IUnknown 인터페이스를 구현해야 합니다. 상태 개체를 사용하여 콜백에 필요한 상태 정보를 저장할 수 있습니다. 상태 정보가 필요하지 않은 경우 이 매개 변수를 NULL로 설정할 수 있습니다. Begin 메서드에는 해당 메서드와 관련된 추가 매개 변수가 포함될 수 있습니다.

Begin 메서드가 실패 코드를 반환하는 경우 작업이 즉시 실패하고 콜백이 호출되지 않음을 의미합니다. Begin 메서드가 성공하면 작업이 보류 중이며 작업이 완료되면 콜백이 호출됩니다.

예를 들어 IMFByteStream::BeginRead 메서드는 바이트 스트림에서 비동기 읽기 작업을 시작합니다.

    BYTE data[DATA_SIZE];
    ULONG cbRead = 0;

    CMyCallback *pCB = new (std::nothrow) CMyCallback(pStream, &hr);

    if (pCB == NULL)
    {
        hr = E_OUTOFMEMORY;
    }

    // Start an asynchronous request to read data.
    if (SUCCEEDED(hr))
    {
        hr = pStream->BeginRead(data, DATA_SIZE, pCB, NULL);
    }

콜백 메서드는 IMFAsyncCallback::Invoke입니다. 여기에는 IMFAsyncResult 인터페이스에 대한 포인터인 단일 매개 변수 pAsyncResult 가 있습니다. 비동기 작업을 완료하려면 비동기 Begin 메서드와 일치하는 End 메서드를 호출합니다. End 메서드는 항상 IMFAsyncResult 포인터를 사용합니다. Invoke 메서드에서 받은 것과 동일한 포인터를 항상 전달합니다. End 메서드를 호출할 때까지 비동기 작업이 완료되지 않습니다. Invoke 메서드 내에서 End 메서드를 호출하거나 다른 스레드에서 호출할 수 있습니다.

예를 들어 바이트 스트림에서 IMFByteStream::BeginRead 를 완료하려면 IMFByteStream::EndRead를 호출합니다.

    STDMETHODIMP Invoke(IMFAsyncResult* pResult)
    {
        m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);

        SetEvent(m_hEvent);

        return S_OK;
    }

End 메서드의 반환 값은 비동기 작업의 상태 나타냅니다. 대부분의 경우 애플리케이션은 비동기 작업이 성공적으로 완료되었는지 여부에 관계없이 일부 작업을 수행합니다. 여러 옵션이 있습니다.

  • Invoke 메서드 내에서 작업을 수행합니다. 이 방법은 애플리케이션이 호출 스레드를 차단하거나 Invoke 메서드 내에서 아무것도 기다리지 않는 한 허용됩니다. 호출 스레드를 차단하는 경우 스트리밍 파이프라인을 차단할 수 있습니다. 예를 들어 일부 상태 변수를 업데이트할 수 있지만 동기 읽기 작업을 수행하거나 뮤텍스 개체를 기다리지 않습니다.
  • Invoke 메서드에서 이벤트를 설정하고 즉시 반환합니다. 애플리케이션의 호출 스레드는 이벤트를 대기하고 이벤트가 신호를 받으면 작업을 수행합니다.
  • Invoke 메서드에서 프라이빗 창 메시지를 애플리케이션 창에 게시하고 즉시 반환합니다. 애플리케이션은 메시지 루프에서 작업을 수행합니다. SendMessage가 콜백 스레드를 차단할 수 있으므로 SendMessage가 아닌 PostMessage를 호출하여 메시지를 게시해야 합니다.

Invoke는 다른 스레드에서 호출된다는 점을 기억해야 합니다. 애플리케이션은 Invoke 내에서 수행되는 모든 작업이 스레드로부터 안전한지 확인할 책임이 있습니다.

기본적으로 Invoke 를 호출하는 스레드는 콜백 개체의 동작을 가정하지 않습니다. 필요에 따라 IMFAsyncCallback::GetParameters 메서드를 구현하여 콜백 구현에 대한 정보를 반환할 수 있습니다. 그렇지 않으면 이 메서드는 E_NOTIMPL 반환할 수 있습니다.

    STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
    {
        // Implementation of this method is optional.
        return E_NOTIMPL;
    }

Begin 메서드에서 상태 개체를 지정한 경우 IMFAsyncResult::GetState를 호출하여 콜백 메서드 내부에서 검색할 수 있습니다.

비동기 콜백 메서드