我正在構建一個模擬器來測試一個非常簡單的機器人的學生代碼。我需要定期在不同的線程上運行兩個功能(更新機器人傳感器和機器人位置)。我目前的實現是高效率的處理器,因爲它有一個線程專門用於簡單地遞增數字以跟蹤代碼中的位置。我最近的理論是,我可以使用睡眠來給出更新傳感器值和機器人位置之間的時間延遲。我的第一個問題是:這是否有效?第二:有沒有辦法做簡單的事情,但測量時鐘週期而不是秒?使用線程定時調用函數
回答
通過等待類似互斥體的對象使線程進入睡眠通常是有效的。一種常見的模式包括等待一個超時的互斥體。達到超時時間後,時間間隔結束。當互斥體被釋放時,它是線程終止的信號。
僞代碼:
void threadMethod() {
for(;;) {
bool signalled = this->mutex.wait(1000);
if(signalled) {
break; // Signalled, owners wants us to terminate
}
// Timeout, meaning our wait time is up
doPeriodicAction();
}
}
void start() {
this->mutex.enter();
this->thread.start(threadMethod);
}
void stop() {
this->mutex.leave();
this->thread.join();
}
在Windows系統中,超時通常以毫秒爲單位指定和精確到大約16內毫秒(timeBeginPeriod()
可能能夠改善這一點)。我不知道CPU週期觸發的同步原語。在委派給OS線程調度器之前,有一些稱爲「關鍵部分」的輕量級互斥體,可讓CPU旋轉幾千個週期。在這段時間內,它們相當準確。
在Linux系統上,準確度可能會高一些(高頻定時器或無滴答內核),除了互斥鎖之外,還有類似於Windows臨界區的「futexes」(快速互斥鎖)。
我不知道我抓住你想要達到什麼樣的,但如果你想測試學生的代碼,你可能想要使用虛擬時鐘和控制自己時間的流逝。例如,通過調用學生必須提供的processInputs()
和decideMovements()
方法。每次通話後,1個時隙到了。
是的,你的理論是正確的。你可以使用睡眠來在線程執行一個函數之間放一些延遲。效率取決於您可以選擇多大的延遲以獲得期望的結果。 你必須解釋你的實施細節。例如,我們不知道兩個線程是否有依賴關係(在這種情況下,您必須注意可能會導致一些週期的同步)。
你可以使用'sleep()',是的。但是在大多數情況下,這可能是一個非常糟糕的主意(你可能會忙於等待)。更合適的方法是使用定時信號/條件變量。 – 2014-10-27 18:22:24
這個C++ 11代碼使用std::chrono::high_resolution_clock
來測量亞秒的時間,而std::thread
運行三個線程。 std::this_thread::sleep_for()
函數用於在指定的時間內休眠。
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
void seconds()
{
using namespace std::chrono;
high_resolution_clock::time_point t1, t2;
for (unsigned i=0; i<10; ++i) {
std::cout << i << "\n";
t1 = high_resolution_clock::now();
std::this_thread::sleep_for(std::chrono::seconds(1));
t2 = high_resolution_clock::now();
duration<double> elapsed = duration_cast<duration<double> >(t2-t1);
std::cout << "\t(" << elapsed.count() << " seconds)\n";
}
}
int main()
{
std::vector<std::thread> t;
t.push_back(std::thread{[](){
std::this_thread::sleep_for(std::chrono::seconds(3));
std::cout << "awoke after 3\n"; }});
t.push_back(std::thread{[](){
std::this_thread::sleep_for(std::chrono::seconds(7));
std::cout << "awoke after 7\n"; }});
t.push_back(std::thread{seconds});
for (auto &thr : t)
thr.join();
}
很難知道這是否符合您的需求,因爲這個問題中缺少很多細節。在Linux下,編譯:我的機器上
g++ -Wall -Wextra -pedantic -std=c++11 timers.cpp -o timers -lpthread
輸出:
0
(1.00014 seconds)
1
(1.00014 seconds)
2
awoke after 3
(1.00009 seconds)
3
(1.00015 seconds)
4
(1.00011 seconds)
5
(1.00013 seconds)
6
awoke after 7
(1.0001 seconds)
7
(1.00015 seconds)
8
(1.00014 seconds)
9
(1.00013 seconds)
其他C++ 11個的標準功能,可能會感興趣的包括timed_mutex和promise/future。
以下是一種方法。我使用C++ 11,線程,原子和高精度時鐘。調度器將回調一個函數,該函數需要dt秒,這是自上次調用以來已過去的時間。如果回調函數返回false,則可以通過調用stop()方法來停止循環。
調度代碼
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
#include <system_error>
class ScheduledExecutor {
public:
ScheduledExecutor()
{}
ScheduledExecutor(const std::function<bool(double)>& callback, double period)
{
initialize(callback, period);
}
void initialize(const std::function<bool(double)>& callback, double period)
{
callback_ = callback;
period_ = period;
keep_running_ = false;
}
void start()
{
keep_running_ = true;
sleep_time_sum_ = 0;
period_count_ = 0;
th_ = std::thread(&ScheduledExecutor::executorLoop, this);
}
void stop()
{
keep_running_ = false;
try {
th_.join();
}
catch(const std::system_error& /* e */)
{ }
}
double getSleepTimeAvg()
{
//TODO: make this function thread safe by using atomic types
//right now this is not implemented for performance and that
//return of this function is purely informational/debugging purposes
return sleep_time_sum_/period_count_;
}
unsigned long getPeriodCount()
{
return period_count_;
}
private:
typedef std::chrono::high_resolution_clock clock;
template <typename T>
using duration = std::chrono::duration<T>;
void executorLoop()
{
clock::time_point call_end = clock::now();
while (keep_running_) {
clock::time_point call_start = clock::now();
duration<double> since_last_call = call_start - call_end;
if (period_count_ > 0 && !callback_(since_last_call.count()))
break;
call_end = clock::now();
duration<double> call_duration = call_end - call_start;
double sleep_for = period_ - call_duration.count();
sleep_time_sum_ += sleep_for;
++period_count_;
if (sleep_for > MinSleepTime)
std::this_thread::sleep_for(std::chrono::duration<double>(sleep_for));
}
}
private:
double period_;
std::thread th_;
std::function<bool(double)> callback_;
std::atomic_bool keep_running_;
static constexpr double MinSleepTime = 1E-9;
double sleep_time_sum_;
unsigned long period_count_;
};
示例用法
bool worldUpdator(World& w, double dt)
{
w.update(dt);
return true;
}
void main() {
//create world for your simulator
World w(...);
//start scheduler loop for every 2ms calls
ScheduledExecutor exec;
exec.initialize(
std::bind(worldUpdator, std::ref(w), std::placeholders::_1),
2E-3);
exec.start();
//main thread just checks on the results every now and then
while (true) {
if (exec.getPeriodCount() % 10000 == 0) {
std::cout << exec.getSleepTimeAvg() << std::endl;
}
}
}
- 1. Boost線程不調用線程函數
- 2. Qt線程調用函數
- 3. 從線程調用函數
- 4. 多線程函數調用
- 5. 多線程調用函數定義在C從TCL線程
- 6. 調用成員函數作爲線程函數使用boost
- 7. 多線程 - 每個線程在特定時間後調用函數
- 8. 使用函數指針從線程調用回調
- 9. C++定時器,線程,定期調用
- 10. 使用預定義函數時回調
- 11. 使用Haskell回調函數調用多線程C FFI時的計劃錯誤
- 12. 從工作線程調用主線程回調函數
- 13. iOS:在回調函數中調用setNeedDisplay時的線程問題
- 14. 使用多線程中的輸入參數調用函數
- 15. 使用C函數時調用函數或程序fopen
- 16. (python)使用線程調用時的不同行爲。定時器
- 17. 如何在成員函數線程中調用回調函數?
- 18. 在新線程powershell中調用函數
- 19. 從主線程函數調用方法
- 20. 線程調用成員函數
- 21. 線程中的iOS調用soap函數
- 22. 參考C++多線程函數調用
- 23. 線程的run()函數調用
- 24. 線程不會調用函數(Python)
- 25. 稍後調用線程函數
- 26. 在OpenMP fortran線程中調用函數
- 27. 與Java交叉線程函數調用
- 28. Python單線程調用函數列表
- 29. 線程中斷與JNI函數調用
- 30. pthread_exit來自線程調用的函數
你能詳細解釋一下你希望做什麼嗎?爲什麼傳感器和位置有不同的線程?這兩個線程是否以任何方式相互依賴?除非測試代碼正在做一些非常繁重的工作,否則我懷疑你需要認真關注優化測試代碼的效率。 – 2014-10-27 18:03:32