【问题标题】:std::thread for class instances用于类实例的 std::thread
【发布时间】:2014-03-31 22:59:58
【问题描述】:

我正在尝试创建此类的两个实例,它们最终将使用 Win32 的 mciSendString 功能播放音乐文件。但是为了测试它,因为这是我第一次尝试使用 std::thread,我编写了一个 test(void) 方法,它输出类 ID,我希望它打印一系列 1 和 2,例如 12122111112212121212 ...

我收到以下错误,test(void) 方法确实存在?

错误 1 ​​错误 C2064:术语不计算为采用 0 个参数的函数

#include <iostream>
#include <thread>

typedef enum MusicStatus {
    MUSIC_PLAYING = 0, 
    MUSIC_PAUSED, 
    MUSIC_STOPPED, 
    MUSIC_IDLE
} MusicStatus, *pMusicStatus;

class MusicPlayer
{
public:

    MusicPlayer(void) {
        m_bIsPlaying = false;
        m_bIsPaused = false;
    }

    bool isPaused(void) {
        return m_bIsPaused;
    }

    bool isPlaying(void) {
        return m_bIsPlaying;
    }

    MusicStatus getState(void) {
        if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
            return MUSIC_IDLE;
        if ( m_bIsPlaying )
            return MUSIC_PLAYING;
        if ( m_bIsPaused ) 
            return MUSIC_PAUSED;
        if ( m_bIsStopped )
            return MUSIC_STOPPED;
        return MUSIC_STOPPED;
    }

    void test(void) {
        for ( int m = 0; m < 100; m++ ) {
            std::cout << this->n;
        }
    }

    int n;

private:

    bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;

};


int main(int argc, char* argv[])
{
    MusicPlayer A;
    MusicPlayer B;
    A.n = 1;
    B.n = 2;

    std::thread t1(A);
    std::thread t2(B);

    t1.join();
    t2.join();

    A.test();
    B.test();

    system("PAUSE");
    return 0;
}

更新:我做了一些调整,现在我遇到了参数列表的问题,错误:MusicPlayer::play_sound 函数调用缺少参数列表

#include <iostream>

#pragma comment(lib, "Strmiids.lib") 

#include <thread>
#include <dshow.h>
#include "Lib/NSL.h"

typedef enum MusicStatus {
    MUSIC_PLAYING = 0, 
    MUSIC_PAUSED, 
    MUSIC_STOPPED, 
    MUSIC_IDLE
} MusicStatus, *pMusicStatus;

class MusicPlayer
{
public:

    MusicPlayer() {
        m_bIsPlaying = false;
        m_bIsPaused = false;
        m_bIsStopped = false;
    }

    bool isPaused() {
        return m_bIsPaused;
    }

    bool isPlaying() {
        return m_bIsPlaying;
    }

    MusicStatus getState() {
        if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
            return MUSIC_IDLE;
        if ( m_bIsPlaying )
            return MUSIC_PLAYING;
        if ( m_bIsPaused ) 
            return MUSIC_PAUSED;
        if ( m_bIsStopped )
            return MUSIC_STOPPED;
        return MUSIC_STOPPED;
    }

    void playAudio(std::string strFilePath) {
        m_strFilePath = strFilePath;
        std::thread audioThread(play_sound);
        audioThread.join();
    }

private:

    bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;
    std::string m_strFilePath;

    void play_sound() {
        IGraphBuilder *pGraph = NULL;
        IMediaControl *pControl = NULL;
        IMediaEvent   *pEvent = NULL;

        // Initialize the COM library.
        HRESULT hr = CoInitialize(NULL);
        if (FAILED(hr))
        {
            printf("ERROR - Could not initialize COM library");
            return;
        }

        // Create the filter graph manager and query for interfaces.
        hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                            IID_IGraphBuilder, (void **)&pGraph);
        if (FAILED(hr))
        {
            printf("ERROR - Could not create the Filter Graph Manager.");
            return;
        }

        hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
        hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

        // Build the graph. IMPORTANT: Change this string to a file on your system.
        hr = pGraph->RenderFile(s2ws(m_strFilePath).c_str(), NULL);
        if (SUCCEEDED(hr))
        {
            // Run the graph.
            hr = pControl->Run();
            if (SUCCEEDED(hr))
            {
                // Wait for completion.
                long evCode;
                pEvent->WaitForCompletion(INFINITE, &evCode);

                // Note: Do not use INFINITE in a real application, because it
                // can block indefinitely.
            }
        }
        pControl->Release();
        pEvent->Release();
        pGraph->Release();
        CoUninitialize();
    }

};

int main(void)
{
    MusicPlayer A;
    A.playAudio("music.mp3");
    system("pause");
    return 0;
}

【问题讨论】:

    标签: c++ multithreading class c++11


    【解决方案1】:

    你不能运行一个对象!您可以运行的是特定对象上的成员函数:std::thread 需要被告知线程的入口函数。它使用第一个构造函数参数作为函数对象,将所有其他参数作为参数用于如何调用函数。由于您的类没有函数调用运算符,std::thread 不知道要调用哪个函数。

    有一些方法可以解决问题:

    1. 您为您的MusicPlayer 类型提供函数调用operator()() 作为线程的入口函数。
    2. 您将成员函数用作第一个参数,并将实际对象用作传递的参数,例如,std::thread t1(&amp;MusicPlayer::test, &amp;A)
    3. 您使用易于绑定的函数对象作为std::thread 的参数,例如std::thread t1(std::bind(&amp;MusicPlayer::test, std::ref(A))

    【讨论】:

    【解决方案2】:

    好的,我已经解决了我的问题,由于 std::thread,std::thread 非常适合在后台播放 mp3 文件。注意:audioThread(&MusicPlayer::play_sound, this);

    #include <iostream>
    
    #pragma comment(lib, "Strmiids.lib") 
    
    #include <thread>
    #include <dshow.h>
    #include "Lib/NSL.h"
    
    typedef enum MusicStatus {
        MUSIC_PLAYING = 0, 
        MUSIC_PAUSED, 
        MUSIC_STOPPED, 
        MUSIC_IDLE
    } MusicStatus, *pMusicStatus;
    
    class MusicPlayer
    {
    public:
    
        MusicPlayer() {
    
            m_bIsPlaying = false;
            m_bIsPaused = false;
            m_bIsStopped = false;
            m_pControl = NULL;
            m_pEvent = NULL;
            m_pGraph = NULL;
            m_pEventEx = NULL;
            m_pBasicAudio = NULL;
            m_pMediaSeeking = NULL;
    
            // Initialize the COM library
            m_hr = CoInitialize(NULL);
            if (FAILED(m_hr)) { // Could not initialize COM library");
                return;
            }
    
            // Create the filter graph manager and query for interfaces.
            m_hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&m_pGraph);
    
            if (FAILED(m_hr)) { // Could not create the Filter Graph Manager
                return;
            }
    
            m_hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **)&m_pControl);
            m_hr = m_pGraph->QueryInterface(IID_IMediaEvent, (void **)&m_pEvent);
            m_hr = m_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&m_pEventEx);
            m_hr = m_pGraph->QueryInterface(IID_IBasicAudio, (void**)&m_pBasicAudio);
            m_hr = m_pGraph->QueryInterface(IID_IMediaSeeking, (void**)&m_pMediaSeeking);
        }
    
        ~MusicPlayer() {
            m_pControl->Release();
            m_pEvent->Release();
            m_pEventEx->Release();
            m_pGraph->Release();
            m_pBasicAudio->Release();
            m_pMediaSeeking->Release();
            CoUninitialize();
        }
    
        bool isPaused() {
            return m_bIsPaused;
        }
    
        bool isPlaying() {
            return m_bIsPlaying;
        }
    
        MusicStatus getState() {
            if ( !m_bIsPlaying && !m_bIsPaused && !m_bIsStopped )
                return MUSIC_IDLE;
            if ( m_bIsPlaying )
                return MUSIC_PLAYING;
            if ( m_bIsPaused ) 
                return MUSIC_PAUSED;
            if ( m_bIsStopped )
                return MUSIC_STOPPED;
            return MUSIC_STOPPED;
        }
    
        void playAudio(std::string strFilePath) {
            m_strFilePath = strFilePath;
            set_state(MUSIC_PLAYING);
            std::thread audioThread(&MusicPlayer::play_sound, this);
            audioThread.join();
        }
    
        bool stopAudio() {
            if ( getState() == MUSIC_PLAYING && m_pControl ) {
                m_hr = m_pControl->Stop();
                if ( SUCCEEDED(m_hr) ) {
                    set_state(MUSIC_STOPPED);
                    return true;
                }
            }
            return false;
        }
    
        bool pauseAudio() {
            if ( getState() == MUSIC_PLAYING && m_pControl ) {
                return SUCCEEDED(m_pControl->Pause());
            }
            return false;
        }
    
        long volume() {
            if ( m_bIsPlaying && m_pBasicAudio ) {
                long lVolume = -1;
                m_hr = m_pBasicAudio->get_Volume(&lVolume);
                if ( SUCCEEDED(m_hr) )
                    return lVolume;
            }
            return -1;
        }
    
        bool setVolume(long lVolume) {
            if ( m_bIsPlaying && m_pBasicAudio ) {
                m_hr = m_pBasicAudio->put_Volume(lVolume);
                return SUCCEEDED(m_hr);
            }
            return false;
        }
    
        long durationInSeconds() {
            return m_ulTrackDuration / 10000000;
        }
    
        __int64 currentPosition() {
            if ( getState() == MUSIC_PLAYING && m_pMediaSeeking ) {
                __int64 curPosition = -1;
                m_hr = m_pMediaSeeking->GetCurrentPosition(&curPosition);
                if ( SUCCEEDED(m_hr) )
                    return curPosition;
            }
            return -1;
        }
    
        bool setPosition(__int64* pCurrentPos, __int64* pStop, bool bAbsolutePositioning) {
            if ( getState() == MUSIC_PLAYING && m_pMediaSeeking ) {
                DWORD flags = 0;
                if ( bAbsolutePositioning )
                    flags = AM_SEEKING_AbsolutePositioning | AM_SEEKING_SeekToKeyFrame;
                else
                    flags = AM_SEEKING_RelativePositioning | AM_SEEKING_SeekToKeyFrame;
                m_hr = m_pMediaSeeking->SetPositions(pCurrentPos, flags, pStop, flags);
                if ( SUCCEEDED(m_hr) )
                    return true;
            }
            return false;
        }
    
    private:
    
        bool m_bIsPlaying, m_bIsPaused, m_bIsStopped;
        std::string m_strFilePath;
    
        HRESULT m_hr;
        IGraphBuilder *m_pGraph;
        IMediaControl *m_pControl;
        IMediaEvent   *m_pEvent;
        IMediaEventEx *m_pEventEx;
        IBasicAudio   *m_pBasicAudio;
        IMediaSeeking *m_pMediaSeeking;
    
        // 10,000,000 per second
        __int64 m_ulTrackDuration;
    
        void set_state(MusicStatus m) {
            switch(m) {
            case MUSIC_STOPPED:
                m_bIsStopped = true;
                m_bIsPlaying = m_bIsPaused = false;
                break;
            case MUSIC_PAUSED:
                m_bIsPaused = true;
                m_bIsPlaying = m_bIsStopped = false;
                break;
            case MUSIC_PLAYING:
                m_bIsPlaying = true;
                m_bIsPaused = m_bIsStopped = false;
                break;
            case MUSIC_IDLE:
                m_bIsPaused = m_bIsPlaying = m_bIsStopped = false;
                break;
            }
        }
    
        void play_sound() {
            m_hr = m_pGraph->RenderFile(s2ws(m_strFilePath).c_str(), NULL);
            if (SUCCEEDED(m_hr))
            {
                m_hr = m_pControl->Run();
                if (SUCCEEDED(m_hr)) {
                    if ( m_pMediaSeeking ) {
                        m_pMediaSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME);
                        m_pMediaSeeking->GetDuration(&m_ulTrackDuration);
                    }
                }
            }
    
        }
    
    };
    
    int main(void)
    {
        MusicPlayer A;
        A.playAudio("music.mp3");
        std::cout << A.durationInSeconds();
        system("pause");
        return 0;
    }
    

    【讨论】:

    • 您是否获得了对MusicPlayer 的函数play_sound 的引用和当前对象的引用并已将其发送到线程?你知道这到底是怎么执行的吗? ?
    【解决方案3】:

    std::thread 用作MusicPlayer 类的成员,并通过将线程函数分配给它来启动后台线程,使其状态变为MUSIC_PLAYING

    【讨论】:

      【解决方案4】:

      小问题:

      MusicPlayer(void)
      bool isPaused(void)
      bool isPlaying(void)
      

      零参数的函数定义为:

      MusicPlayer()
      bool isPaused()
      bool isPlaying()
      

      主要问题。

      线程对象构造函数采用函子。因为您不传递任何参数,所以仿函数也必须采用零参数。这意味着您传递给线程的对象必须像这样可以调用:

      MusicPlayer A;
      std::thread t1(A);
      
      // This means that the object A is callable like a function.
      A();
      
      // For this to work the class MusicPlayer must define the opropriate function operator:
      
      class MusicPlayer
      {
          public:
              void operator()() { /* Code run inside thread */ }
      };
      

      【讨论】:

      • 小问题?我被告知使用 void 来表示没有参数会加快编译时间。也许这是一个神话。
      • @johnsonwi:没有参数是 C++ 的做法。在其中使用 void 仅是为了与 C stackoverflow.com/a/7412299/14065 兼容
      【解决方案5】:

      你可以试试

      std::thread audioThread(([this](){MusicPlayer::play_sound();};
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-21
        • 2014-01-23
        • 2012-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多