簡體   English   中英

C ++ 11線程修改std :: list

[英]C++11 thread to modify std::list

我將發布我的代碼,然后告訴您我在做什么。

#include <thread>
#include <mutex>
#include <list>
#include <iostream>

using namespace std;

...

//List of threads and ints
list<thread> threads;
list<int> intList;

//Whether or not a thread is running
bool running(false);

//Counters
int busy(0), counter(0);

//Add 10000 elements to the list
for (int i = 0; i < 10000; ++i){
    //push back an int
    intList.push_back(i);
    counter++;
    //If the thread is running, make a note of it and continue
    if (running){
        busy++;
        continue;
    }
    //If we haven't yet added 10 elements before a reset, continue
    if (counter < 10)
        continue;
    //If we've added more than 10 ints, and there's no active thread,
    //reset the counter and launch
    counter = 0;
    threads.push_back(std::thread([&]
        //These iterators are function args
        (list<int>::iterator begin, list<int>::iterator end){
        //mutex for the running bool
        mutex m;
        m.lock();
        running = true;
        m.unlock();

        //Remove either 10 elements or every element till the end
        int removed(0);
        while (removed < 10 && begin != end){
            begin = intList.erase(begin);
            removed++;
        }

        //unlock the running bool
        m.lock();
        running = false;
        m.unlock();
        //Pass into the thread func the current beginning and end of the list
    }, intList.begin(), intList.end()));
}

for (auto& thread : threads){
    thread.join();
}

我認為這段代碼正在做的是在列表末尾添加10000個元素。 對於我們添加的每10個,啟動一個(單個)線程,該線程將刪除列表的前10個元素(在啟動線程時)。

我不希望這會刪除每個列表元素,我只是想看看在從開頭刪除元素的同時是否可以添加到列表的末尾。 在Visual Studio中,我經常會遇到“ list iterators incompatible ”錯誤,但我認為問題出在跨平台上。

我的想法怎么了? 我知道是這樣

編輯:

因此,我現在看到此代碼非常不正確。 真的,我只希望一次激活一個輔助線程來刪除元素,這就是為什么我盡管調用“擦除”是可以的。 但是,我不知道如何在不加入線程的情況下聲明線程,如果我等待它,那么我真的看不到這樣做的意義。

我應該在循環之前聲明我的線程,讓它等待主線程發出的信號嗎?

為了明確起見,我的目標是執行以下操作:我想抓住一個線程上的鍵盤按鍵並將它們存儲在列表中,並且每隔一段時間將它們記錄到另一個線程上的文件中,同時刪除我記錄的內容。 由於我不想花很多時間寫磁盤,因此我想寫離散塊(共10個)。

感謝克里斯托夫和其他所有人。 現在是我的代碼...我可能沒有正確使用lock_guard。

#include <thread>
#include <mutex>
#include <list>
#include <iostream>
#include <atomic>

using namespace std;

...

atomic<bool> running(false);
list<int> intList;
int busy(0), counter(0);
mutex m;
thread * t(nullptr);

for (int i = 0; i < 100000; ++i){
    //Would a lock_guard here be inappropriate?
    m.lock();
    intList.push_back(i);
    m.unlock();
    counter++;
    if (running){
        busy++;
        continue;
    }
    if (counter < 10)
        continue;
    counter = 0;
    if (t){
        t->join();
        delete t;
    }
    t = new thread([&](){
        running = true;

        int removed(0);
        while (removed < 10){
            lock_guard<mutex> lock(m);
            if (intList.size())
                intList.erase(intList.begin());  
            removed++;
        }
        running = false;
    });
}

if (t){
    t->join();
    delete t;
}

您的代碼不適用於:

  • 您的互斥鎖對於每個線程都是本地的(每個線程都有它自己的副本,僅由它自己使用:沒有線程間同步的機會!)
  • intList不是原子類型,但是您可以從多個線程中訪問它,從而導致競爭條件和未定義的行為。
  • 在創建線程時發送給線程的開始和結束可能在執行期間不再有效。

這里有一些改進(請看注釋行):

atomic<bool> running(false);    // <=== atomic (to avoid unnecessary use of mutex)
int busy(0), counter(0);
mutex l;   // define the mutex here, so that it will be the same for all threads

for (int i = 0; i < 10000; ++i){
    l.lock();    // <===you need to protect each access to the list
    intList.push_back(i);
    l.unlock();  // <===and unlock 
    counter++;
    if (running){
        busy++;
        continue;
    }
    if (counter < 10)
        continue;
    counter = 0;
    threads.push_back(std::thread([&]
        (){    //<====No iterator args as they might be outdated during executionof threads!!
        running = true;    // <=== no longer surrounded from lock/unlock as it is now atomic

        int removed(0);
        while (removed < 10){
            l.lock();       // <====you really need to protect access to the list
            if (intList.size())    // <=== check if elements exist NOW
                intList.erase(intList.begin());  // <===use current data, not a prehistoric outdated local begin !!
            l.unlock();      // <====end of protected section
            removed++;
        }

        running = false;    // <=== no longer surrounded from lock/unlock as it is now atomic
    })); //<===No other arguments
}
...

順便說一句,我建議您看一下lock_guard<mutex>中的鎖,因為這些鎖可以確保在所有情況下都可以解鎖(尤其是在出現此類異常或意外驚喜時)。

編輯:通過使它成為atomic<bool> ,我避免了使用互斥鎖running的鎖定保護。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM