C++11线程修改std::list
C++11 thread to modify std::list
我会 post 我的代码,然后告诉你我认为它在做什么。
#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
”错误,但我认为问题是跨平台的。
我的想法有什么问题吗?我知道这是什么
编辑:
所以我现在看到这段代码是非常不正确的。实际上,我只希望一次激活一个辅助线程来删除元素,这就是为什么我虽然调用 erase 没问题。但是,我不知道如何在不加入线程的情况下声明一个线程,如果我等待它,那么我真的看不到做任何事情的意义。
我应该在循环之前声明我的线程并让它等待来自主线程的信号吗?
澄清一下,我的目标是执行以下操作:我想在一个线程上抓取键盘按下并将它们存储在一个列表中,并且每隔一段时间将它们记录到一个单独线程上的文件中,同时删除这些东西我登录了因为我不想花很多时间写入磁盘,所以我想写入离散块(10 个)。
感谢 Christophe 和其他所有人。现在这是我的代码...我可能使用 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>
中的锁,因为这些可以确保在所有情况下都能解锁(尤其是当有是例外或像这样的惊喜)。
编辑: 我用互斥锁避免了 running
的锁定保护,方法是将其设置为 atomic<bool>
。
我会 post 我的代码,然后告诉你我认为它在做什么。
#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
”错误,但我认为问题是跨平台的。
我的想法有什么问题吗?我知道这是什么
编辑:
所以我现在看到这段代码是非常不正确的。实际上,我只希望一次激活一个辅助线程来删除元素,这就是为什么我虽然调用 erase 没问题。但是,我不知道如何在不加入线程的情况下声明一个线程,如果我等待它,那么我真的看不到做任何事情的意义。
我应该在循环之前声明我的线程并让它等待来自主线程的信号吗?
澄清一下,我的目标是执行以下操作:我想在一个线程上抓取键盘按下并将它们存储在一个列表中,并且每隔一段时间将它们记录到一个单独线程上的文件中,同时删除这些东西我登录了因为我不想花很多时间写入磁盘,所以我想写入离散块(10 个)。
感谢 Christophe 和其他所有人。现在这是我的代码...我可能使用 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>
中的锁,因为这些可以确保在所有情况下都能解锁(尤其是当有是例外或像这样的惊喜)。
编辑: 我用互斥锁避免了 running
的锁定保护,方法是将其设置为 atomic<bool>
。