2016-09-21 47 views
-1

我想運行一個函數,並告訴函數是否在n毫秒後沒有完成,停止該函數並啓動另一個函數。像這樣的代碼:如何停止從c + +外部運行功能

void run() 
{ 
    //do something that doesn't have while(1) 
} 


void main() 
{ 
    run(); 
    if(runFunctionDidntFinishInSeconds(10) 
    { 
     endPrintFunction(); 
     backupPlan(); 
    } 
    return 0; 
} 

我搜索出來,發現boost :: timed_join函數。這是我的代碼:

void run() 
{ 
    int a; 
    for (int i = 0; i < 2000; i++) 
     cout << i << endl; 
} 


int main() 
{ 
    boost::thread t = new boost::thread(&run); 
    if (t.timed_join(boost::posix_time::microseconds(10000))){ 
     cout << "done" << endl; 
    } 
    else{ 
     cout << endl << "not done" << endl; 
    } 


    system("pause"); 
    return 0; 
} 

但它不會停止線程't'運行。我去終止線程,但這不是一個好的選擇。 我想要'a'功能來完成我告訴它的確切時間。 系統每16ms獲得一次輸入,我想對其進行處理,並說如果處理花費的時間超過13ms左右,請執行備份計劃。我希望它能夠從編寫處理方法的人中抽象出來。因此,在它的頂部放一段時間循環會給我帶來延遲。 我該怎麼辦? 至少我認爲我需要的是能夠重置處理線程來完成它需要做的事情!

+1

另一種選擇是讓循環依賴於全局變量('bool keep-running')而不是無限循環。全局通常是不好的做法,但在這樣的情況下,它們可能會導致比替代方案更乾淨的代碼。 – Carcigenicate

+1

聽起來像你需要一個條件變量。保持運行的函數檢查變量,如果它是真的,則函數返回,否則它繼續運行。然後,只需要在線程結束時設置變量。 – NathanOliver

+0

問題是我打電話的方法沒有一段時間(1),我無法像這樣在t中檢查變量,我希望它從打印方法中抽象出來。 – JOOF

回答

0

這裏有兩個和3/4的方法。

第一個要求您要停止的代碼進行合作。它在運行時輪詢某個變量,或者週期性地調用一個可能拋出異常以暫停執行的函數。第二種模式下的可中斷螺紋。

第二個要求您啓動一個新進程,將您的數據編組到該函數,並使用IPC來獲取信息。如果該函數沒有及時返回,則會終止該子進程。

第三個「一半」涉及用不同語言重寫代碼,或使用C++作爲腳本語言。您可以在爲您提供第一個或第二個解決方案的解釋器中運行代碼。


現在,實際的選擇(1/4溶液)是確保該函數是純功能性的,在單獨的線程具有半可靠中止消息運行它(如第一個),並如果時間過長,則丟棄其返回值。這不符合你的要求,但要容易得多。

+0

問題是最後期限是16millisecondes,我希望它是有效的,我打電話的功能很重,我正在做它每16毫秒! – JOOF

2

我認爲你正在尋找類似std :: future的東西。

http://en.cppreference.com/w/cpp/thread/future/wait_for

您可以在另一個線程啓動功能,並等待函數返回或有一個超時。

對於示例:

std::future<void> future = std::async(std::launch::async, print); 

auto status = future.wait_for(std::chrono::seconds(10)); 
if (status == std::future_status::deferred) 
{ 
    std::cout << "deferred\n"; 
} 
else if (status == std::future_status::timeout) 
{ 
    std::cout << "timeout\n"; 
} 
else if (status == std::future_status::ready) 
{ 
    std::cout << "ready!\n"; 
} 

然而,這不會導致分離線程結束。爲此,需要在啓動時包含一個標誌,以便分離的線程可以自行清理並退出。

void run(const std::atomic_bool& cancelled) 
{ 
    int a; 
    for (int i = 0; i < 2000; i++) 
    { 
     cout << i << endl; 
     if (cancelled) 
      return; 
    } 
} 

std::atomic_bool cancellation_token = false; 
std::future<void> future = std::async(std::launch::async, 
             run, 
             std::ref(cancellation_token)); 

auto status = future.wait_for(std::chrono::seconds(10)); 
if (status == std::future_status::deferred) 
{ 
    std::cout << "deferred\n"; 
} 
else if (status == std::future_status::timeout) 
{ 
    std::cout << "timeout\n"; 
    cancellation_token = true; 
} 
else if (status == std::future_status::ready) 
{ 
    std::cout << "ready!\n"; 
} 
+1

即使超時過期,這仍然會保持'std :: async'的活動狀態,但主線程只會繼續。 –

+0

但我該如何結束運行功能? – JOOF

+0

那麼,一旦開始就沒有保存從外部取消線程的方法。在http://stackoverflow.com/a/33315162/6858837中概述了什麼可以在啓動時包含取消標誌。 – Trevir

0

有與作爲信號燈原子公司的方式,但是這將發出飽吹記憶障礙,從而減少由於性能load每次迭代:

#include <iostream> 
#include <thread> 
#include <chrono> 
#include <atomic> 

std::atomic<bool> printFinished { false }; 
std::atomic<bool> shouldPrintRun { true }; 

void print() 
{ 
    while (shouldPrintRun.load() /* && your normal stop condition*/) 
    { 
     //work.. 
    } 
    printFinished.store(true); 
} 


int main() 
{ 
    std::thread t(print); 
    std::this_thread::sleep_for(std::chrono::seconds(10)); 
    if (!printFinished.load()) 
    { 
     shouldPrintRun.store(false); 
     t.join(); 
     std::cout << "help!"; 
    } 
    return 0; 
} 

如果你不想讓你的功能這是在另一個線程上運行以檢查是否需要停止,然後終止該線程是只有選項。

+0

我想打印方法結束後,我告訴它。和打印功能只是一個例子 – JOOF

+0

@JOOF這是不可能的,而不終止'boost :: thread'。 –

+0

@JOOF:你如何定義「完全」?沒有該函數的*許可*,您不能結束函數的執行。這需要你以某種方式與它溝通。這要求該功能在該通信中參與*。唯一的另一種選擇是OS線程終止。 –

0

一個可能的解決方案是,你必須將這個冗長的函數變成小的增量函數,它會在每次從它最後一次離開時調用它時繼續執行任務。下面的代碼可以在一個線程中運行,可以完成類似的時間分割器工作,並且可以隨意終止。

void Process() 
{  
    bool flag = true; 
    while (running) 
    { 
     std::chrono::high_resolution_clock::time_point time1 = std::chrono::high_resolution_clock::now(); 
     std::chrono::milliseconds span(16); 
     while ((std::chrono::high_resolution_clock::now() - time1) < span) 
     { 
      flag ? incremental_function1() : incremental_function2(); 

      if (!running) return; 
     } 
     flag = (!flag); 
    } 
} 
1

我希望它從誰寫的處理方法的那些抽象。

標準C++沒有辦法強行中斷從函數的調用圖之外的功能的控制流(它調用可以拋出一個功能,但有人不能扔他們)。

操作系統特定的線程系統有方法來終止線程。但是,這會使程序處於未定義狀態,因爲任何堆棧變量的析構函數都未被調用。而且由於在殺死它時你不知道處理過程在哪裏,所以你不能有效地清理它。即使是C程序也不能保證任意函數可以被終止;它必須是一個不會動態分配內存或其他必須清理的資源。

您可以通過非常仔細地編寫您的功能來彌補這一點。但是這要求編寫該函數的人非常仔細地編寫它。因此,不存在抽象,因爲寫函數的人必須知道規則是什麼,並且需要遵循它們。

因此,唯一有效的解決方案需要合作。該功能必須以可以通過這些與操作系統相關的功能安全地停止的方式編寫,或者必須寫入該功能以定期檢查某個值並停止本身