我希望为Page
对象的每个实例都有一个线程。一次只能执行其中一个(只是检查指向当前正在运行的线程的指针是否可连接..)
class Page : public std::vector<Step>
{
// ....
void play();
void start(); // check if no other thread is running. if there is a running thread, return. else join starter
std::thread starter; // std::thread running this->play()
static std::thread* current; // pointer to current running thread
// ...
};
我希望能够启动starter
个Page
个对象的线程。例如:
Page x , y , z;
// do some stuff for initialize pages..
x.start();
// do some other work
y.start(); // if x is finished, start y otherwise do nothing
// do some other lengthy work
z.start(); // if x and y are not running, start z
我无法将started
声明为Page
的成员。我发现这是因为std::thread
只能在声明时初始化。 (或类似的东西,导致无法复制线程)
void x()
{
}
//...
std::thread t(x); // this is ok
std::thread r; // this is wrong, but I need this !
r = std::thread(this->y); // no hope
r = std::thread(y); // this is wrong too
答案 0 :(得分:3)
您可以使用成员初始化列表将线程初始化为要运行的函数。例如,考虑Page
的构造函数:
class Page {
public:
Page(); // For example
private:
std::thread toRun;
};
Page::Page() : toRun(/* function to run */) {
/* ... */
}
注意我们如何使用Page
构造函数中的初始化列表将toRun
初始化为应该运行的函数。这样,toRun
被初始化,就像您已将其声明为局部变量
std::string toRun(/* function to run */);
那就是说,我认为你必须在代码中解决两个主要问题。首先,您应该不继承std::vector
或任何标准集合类。这些类的析构函数没有标记为virtual
,这意味着如果您尝试将Page
视为std::vector
,则可以轻松调用未定义的行为。相反,请考虑让Page
将std::vector
作为直接子对象。此外,您不应公开该类的std::thread
成员。作为一般规则,数据成员应该private
来增加封装,以便将来更容易修改类,并防止人们破坏所有类的不变量。
希望这有帮助!
答案 1 :(得分:2)
永远不要公开继承std
容器,除非代码是丢弃代码。老实说,当推动代码时,抛弃代码的频率会变成生产代码。
我知道您不想重现整个std::vector
界面。这是繁琐的写作,难以维护,并且诚实地可以制造错误。
试试这个
class Page: private std::vector
{
public:
using std::vector::push_back;
using std::vector::size;
// ...
};
忽略std::vector
问题,这应该适用于问题的并发部分。
class Page
{
~Page( void )
{
m_thread.join();
}
void start( void );
private:
// note this is private, it must be to maintain the s_running invariant
void play( void )
{
assert( s_current == this );
// Only one Page at a time will execute this code.
std::lock_guard<std::mutex> _{ s_mutex };
s_running = nullptr;
}
std::thread m_thread;
static Page* s_running;
static std::mutex s_mutex;
};
Page* Page::s_running = nullptr;
std::mutex Page::s_mutex;
std::condition Page::s_condition;
void Page::start( void )
{
std::lock_guard<std::mutex> _{ s_mutex };
if( s_running == nullptr )
{
s_running = this;
m_thread = std::thread{ [this](){ this->play(); } };
}
}
如果在Page
之前main()
实例化,则此解决方案可能会出现初始化顺序问题