std::class 实例的线程

std::thread for class instances

本文关键字:线程 class std 实例      更新时间:2023-10-16

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

...我收到以下错误,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::p lay_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;
}

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

有一种方法可以解决此问题:

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

好的,我已经解决了我的问题,由于 std::thread,它似乎是在后台播放 mp3 文件的理想选择。 注意:audioThread(&MusicPlayer::p lay_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;
}

使用std::thread作为MusicPlayer类的成员,并在更改为状态MUSIC_PLAYING时通过为其分配线程函数来启动后台线程。

小问题:

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 */ }
};

你可以尝试类似的东西

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