下面是一些代碼,它可以使幾個計時器平行遞增:
main.cpp
using namespace std;
#include <stdio.h>
#include <time.h>
#include <iostream>
#include <math.h>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <thread>
#include <vector>
#include <future>
#include "mychrono.hpp"
int main()
{
std::vector<Chronometer*> car_crono;
Chronometer chrono, output_chrono。
std::vector<std::thread> threads。
std::vector<std::future<Chronometer&>futures。
std::執行緒th;
/future<Chronometer> ft;
for(int i = 0; i < 2; i )
{
car_crono.push_back(new Chronometer)。
}
while (1) {
for(int i = 0; i<2; i )
{
//
//threads.push_back(std::thread(&Chronometer::start_chrono, car_crono[i], std::ref(chronono));
// auto ft = std::async(std::launch::async, &Chronometer::start_chrono, car_crono[i], std::ref(Chrono));
//
//std::cout << "Hello-world" << std::endl;
futures.emplace_back(std::async(std:: launch::async, &Chronometer::start_chrono, car_crono[i], std::ref(chronono) )。
}
std::cout << "hello-world" << std::endl;
//auto ft = std::async(std::launch::async, &Chronometer::start_chrono, car_crono[0], std::ref(chronono));
//std::cout << "Hello-world-2" << std::endl;/span>
for(auto& & f: futures){
std::cout << f.get() << '
'。
}
}
car_crono.clear()。
}
mychrono.cpp
#include "mychrono.hpp"/span>
#include <time.h>
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sstream>
#include <thread>
//int Chronometer::hour(0), min(0), sec(0);
Chronometer::Chronometer() 。hour(0) 。min(0), sec(0)
{
}
Chronometer& Chronometer::start_chrono(Chronometer& chrono)
{
// if(chrono.hour == 0 && chrono.min == 0 && chrono.sec == 0)
// {
bool condition = true。
while(condition) {
sleep(1)。
chrono.sec ;
if(chronono.sec > 59) {
chrono.min ;
chrono.sec = 0;
}
if(Chrono.min > 59) {
chrono.hour ;
chrono.sec = 0;
chrono.min = 0;
}
// if(chrono.sec == 10)
// {
// condition = false;
// }
std::cout << "Chrono: " << chrono << std::endl;
}
return chrono;
//}。
}
Chronometer& Chronometer::finish_chrono(Chronometer& chrono)
{
chrono.hour = 0;
chrono.sec = 0;
chrono.min = 0;
return chrono;
}
std::ostream& operator<<(std::ostream& flux, Chronometer t)
{
flux << t.hour << ":" << t.min << ":" << t.sec。
return flux;
}
Chronometer& Chronometer::operator=(const Chronometer& other)
{
//Guard self assignment
//if (this == & other)
return *this。
}
Chronometer::~Chronometer(){}。
mychrono.hpp
#include <time.h>/span>
#include <iostream>
#include <sstream>
#ifndef mychrono_hpp
#define mychrono_hpp
class Chronometer
{
private:
int hour, min, sec;
//std::stringstream ss;.
//Chronometer chrono;
public:
Chronometer()。
Chronometer& start_chrono(Chronometer& chrono)。
Chronometer& finish_chrono(Chronometer& chrono)。
friend std::ostream& operator<<(std::ostream& flux, Chronometer t)。
Chronometer& operator=(constChronometer& other)。
~Chronometer()。
};
#endif。
我的程式運行良好,我的兩個計時器相互平行,但仍然依賴于我的while回圈。例如,在這里我將列印 "hello-world "一次,但需要等待我的執行緒停止,以便在我的while回圈中列印第二個 "hello-world "訊息。
我的問題是,如何使我的執行緒并行運行,并且完全不受我的while回圈中其他指令的影響?
uj5u.com熱心網友回復:
Tzig有一個和我類似的想法,那就是使用條件變數之類的。 我做了一個完整的作業實體,包括注釋,希望寫得可讀性。
#include <Chrono>
#include <iostream>
#include <ioomanip>
#include <mutex>
#include <future>
#include <condition_variable>/span>
//-----------------------------------------------------------------------------------------------------
/span>定時器的狀態。
enum class State
{
閑置。
啟動中
運行中
停止。
停止
};
//-----------------------------------------------------------------------------------------------------
///用于使用std::condition_variable的輔助類,使代碼更易讀。
///考慮到了條件變數的陷阱。
//https://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables
template<typename T>
class StateVariable
{
public:
StateVariable() = delete;
StateVariable(const StateVariable&) = delete;
StateVariable(StateVariable& &) = delete;
StateVariable& operator=(const StateVariable& ) = delete;
explicit StateVariable(const T& value) :
m_value{ value }。
{
}
void operator=(const T& value) noexcept
{
{
std::unique_lock<std::mutex> lock(m_value_mutex)。
m_value = value。
}
m_value_changed.notify_all()。
}
//原子檢查和設定。
T set_if(const T& from_value, constT& to_value) noexcept
{
{
std::unique_lock<std::mutex> lock(m_value_mutex);
if (m_value != from_value) return from_value;
m_value = to_value;
}
m_value_changed.notify_all()。
return to_value。
}
const bool try_wait_for(const T& value, const std: :Chrono::stable_clock::duration& duration) const noexcept
{
auto pred = [this, value] { return (m_value == value); };
std::unique_lock<std::mutex> lock(m_value_mutex) 。
if (pred()) return true;
return m_value_changed.wait_for(lock, duration, pred)。
}
void wait_for(constT& value) const
{
try_wait_for(value, std::Chrono::stable_clock::duration::max()。
}
private:
// mutables 所以我可以在等待時做出const的承諾。
//他們不會改變可觀察的狀態(m_value)。
//這個類的。
mutable std::mutex m_value_mutex。
mutable std::condition_variable m_value_changed;
std::atomic<T> m_value。
};
//-----------------------------------------------------------------------------------------------------
//用于存盤經過的時間的輔助類,有助于以后的可讀性。
class ElapsedTime
{
public:
explicit ElapsedTime(const std::chrono::stable_clock::duration& duration) :
m_duration{ duration }。
{
}
auto hours() const
{
return std::Chrono::duration_cast<std::Chrono::hours>(m_duration).count()。
}
auto minutes() const
{
return (std::Chrono::duration_cast<std::Chrono::minutes> (m_duration).count() % 60)。
}
auto seconds() const
{
return (std::Chrono::duration_cast<std::Chrono::seconds> (m_duration).count() % 60)。
}
private:
std::Chrono::stable_clock::duration m_duration。
};
//-----------------------------------------------------------------------------------------------------
//ElapsedTime的格式化。
std::ostream& operator<<(std::ostream& os, const ElapsedTime& t)
{
os << std::setfill('0) << std::setw(2) < t. hours() << ' :';
os << std::setfill('0') << std::setw(2) << t。 minutes() << ' :';
os << std::setfill('0') << std::setw(2) << t。 seconds()。
return os。
}
//-----------------------------------------------------------------------------------------------------
//ChronoMeter類
//注意我使用了std::chono類。
class ChronoMeter final
{
public:
ChronoMeter() :
m_state{ State::idle },
m_duration{ std::Chrono::stable_clock::duration::min() }.
{
};
ChronoMeter(const ChronoMeter&) = delete;
ChronoMeter(ChronoMeter& &) = delete;
ChronoMeter& operator=(const ChronoMeter& ) = delete;
void Start()
{
m_start_time = std::Chrono::stable_clock::now()。
//為讀者提供練習,也允許停止的Chronometers被重新啟動。。
//目前只有這個簡單的狀態模型。
if (m_state.set_if(State::idle, State::starting) != State::starting)
{
throw std::runtime_error("只有空閑的ChronoMeter才能被啟動")。
}
//它可以捕捉到 "這個",因為的析構器是可以的。
// chronometer通過future與這個執行緒的終止同步。
m_future = std::async(std:: launch::async, [this]
{
//設定執行緒真正開始的指示。。
//這很重要,因為當std::async回傳時,這個執行緒就存在。
//>但可能還沒有被調度。
m_state = State::running。
do
{
//為m_duration賦值并不是原子性的,所以要保護它。
//我們可能會在另一個執行緒上讀取這個值,而這個執行緒可能會。
/// 導致讀取一個中間狀態。
std::scoped_lock<std::mutex> lock{ m_data_mtx };
m_duration = std::Chrono::stable_clock::now() - m_start_time。
//使用statevariable來檢查停止意味著它可以做出反應。
//在一秒的延遲期間,立即停止。
//這是比使用sleep的優勢。
} while (!m_state.try_wait_for(State::stopping, std::Chrono::seconds(1)) 。)
m_state = State::stoped;
});
//等待執行緒真正開始。
//這樣,我們就有了一個明確的啟動后條件。
m_state.wait_for(State::running)。
}
void Stop()
{
//只允許運行中的Chronometer被停止。{
//在所有其他狀態下,停止不做任何事情。
if (m_state.set_if(State::running, State::stopping) == State::stopping)
{
//與停止狀態同步,由其他執行緒設定。
m_state.wait_for(State::stoped)。
//span>未來的獲取對于同步來說并不是真的需要。
//但是如果執行緒拋出了例外,就會在這里重新拋出。
m_future.get()。
}
}
~ChronoMeter()
{
//自動停止執行緒,如果這還沒有發生。。
Stop()。
}
const ElapsedTime Elapsed() const
{
std::scoped_lock<std::mutex> lock{ m_data_mtx }。
return ElapsedTime{ m_duration };
}
private:
std::future<void> m_future;
StateVariable<State> m_state。
mutable std::mutex m_data_mtx;
std::Chrono::stepid_clock::time_point m_start_time。
std::Chrono::stable_clock::duration m_duration。
};
int main()
{
ChronoMeter meter1;
ChronoMeter meter2。
meter1.Start()。
std::this_thread::sleep_for(std::Chrono::seconds(5) 。)
auto elapsed_1_1 = meter1.Elapsed()。
std::cout << "meter 1 elapsed time" << elapsed_1_1 << std::endl;
meter2.Start()。
std::this_thread::sleep_for(std::Chrono::seconds(4) 。)
auto elapsed_1_2 = meter1.Elapsed()。
auto elapsed_2 = meter2.Elapsed()。
std::cout << "meter 1 elapsed time" << elapsed_1_2 << std::endl;
std::cout << "Meter 2 elapsed time" << elapsed_2 << std::endl;
meter1.Stop()。
//不明確停止meter2(和它的執行緒),如果需要,這將由析構器安全地完成。
return 0。
uj5u.com熱心網友回復:
我通常通過讓多執行緒物件處理所有與多執行緒有關的事情來解決這個問題,下面是我在你的案例中的解決方法(我最后重寫了很多東西,所以可能行為并不完全是你想要的,你可以把我的代碼作為一個起點):
main.cpp.com
main.cpp:
#include <iostream>
#include <vector>
#include "mychrono.hpp"
int main()
{
std::vector<Chronometer*> car_crono;
for(int i = 0; i < 2; i )
{
car_crono.push_back(new Chronometer)。
}
while (1) {
// std::cout << "hello-world" << std::endl;/span>
Chronometer::Time t = car_crono[0]->get_time()。
if(t.sec >=10)
car_crono[0]->reset_chrono()。
std::cout << "Seconds of T0: " << t.sec << std::endl;
std::cout << "T1: " << car_crono[1]->to_string() << std::endl;
}
car_crono.clear()。
}
mychrono.hpp:
#ifndef mychrono_hpp
#define mychrono_hpp
#include <iostream>
#include <thread>
#include < memory>
#include <condition_variable>/span>
#include <mutex>
#include <atomic>
class Chronometer
{
public:
struct Time {
int小時。
int min;
int sec;
};
Chronometer()。
void reset_chrono。
friend std::ostream& operator<<(std::ostream& flux, Chronometer& t)。
Chronometer& operator=(constChronometer& other)。
std::string to_string()。
Time get_time()。
~Chronometer()。
private:
時間currentTime。
std::mutex timeMutex。
std::condition_variable conditionVariable。
std::unique_ptr<std::thread> thread。
std::mutex CVMutex;
std::atomic<bool> exitNow;
void thread_function()。
};
#endif>
mychrono.cpp:
#include "mychrono.hpp"/span>
Chronometer::Chronometer() : currentTime.hour(0), currentTime. min(0), currentTime.sec(0)
{
thread.reset(new std::thread(&Chronometer::thread_function, this) )。)
}
void Chronometer::reset_chrono()
{
std::lock_guard<std::mutex> lock(timeMutex)。
currentTime.hour = 0;
currentTime.sec = 0;
currentTime.min = 0;
}
std::ostream& operator<<(std::ostream& flux, Chronometer& t)
{
flux << t.to_string()。
return flux;
}
Chronometer& Chronometer::operator=(const Chronometer& other)
{
//Guard self assignment
//if (this == & other)
return *this。
}
std::string Chronometer::to_string()
{
std::lock_guard<std::mutex> lock(timeMutex)。
return std::to_string(currentTime.hour) ":" std::to_string(currentTime. min) ":" std::to_string(currentTime.sec)。
}
Time Chronometer::get_time()
{
return currentTime。
}
Chronometer::~Chronometer()
{
exitNow = true。
{
std::unique_lock<std::mutex> lock(CVMutex)。
lock.unlock()。
conditionVariable.notify_all()。
}
thread->join()。
}
void Chronometer::thread_function()
{
std::unique_lock<std::mutex> waitLock(CVMutex)。
while(! exitNow)
{
sec ;
if(currentTime.sec > 59) {
std::lock_guard<std::mutex> lock(timeMutex)。
currentTime.min ;
currentTime.sec = 0;
}
if(currentTime.min > 59) {
std::lock_guard<std::mutex> lock(timeMutex)。
currentTime.hour ;
currentTime.sec = 0;
currentTime.min = 0;
}
// std::cout << "chronono: " << *this << std::endl; //不是執行緒安全的,要小心。
conditionVariable.wait_for(waitLock, std::Chrono::seconds(1))。
}
編輯:關于你的最新評論:你不需要在其析構器中重置一個計時器,因為資料無論如何都會被銷毀。如果你想在它運行時重置計數器,你需要從你的主函式中呼叫Chronometer::reset_chrono()。
對于你評論的第二部分,我在代碼中添加了一個get_time函式(我還添加了一個mutex以避免資料競賽,我在寫原始答案時完全忘記了)。當你想從主函式中獲得一個計時器的當前時間時,你只需呼叫get_time()并使用它回傳的結構來獲得你想要的資訊。
我添加了一個小例子來展示如何使用這兩個函式。正如你所看到的,主函式甚至不需要知道什么是執行緒!
我可能是錯的,但我想說的是,我不需要知道什么是執行緒。
我可能是錯的,但從你問的問題來看,我覺得你可能不習慣多執行緒的作業方式。這是一個非常困難的概念,也是我覺得你不能只通過經驗來學習的少數概念之一,如果是這樣的話,你可能想從專門的網站上了解它,比如這個網站。我想我拼湊出了你會說法語,這里有一篇關于它的理論的非常好的文章(顯然沒有完成)和另一篇法語的,更多關于C 的具體情況。如果你理解了核心概念,只是對我的代碼有困難,我打算把它全部注釋出來,但現在Pepijn Kramer在他們的回應中做了很好的解釋。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/314169.html
標籤:
