Following is just a simple program to test using two threads to insert a hash table. For test no lock is used.
以下是使用两个线程插入哈希表进行测试的简单程序。对于测试,不使用锁定。
#include <iostream>
#include <unordered_map>
#include <thread>
using namespace std;
void thread_add(unordered_map<int, int>& ht, int from, int to)
{
for(int i = from; i <= to; ++i)
ht.insert(unordered_map<int, int>::value_type(i, 0));
}
void test()
{
unordered_map<int, int> ht;
thread t[2];
t[0] = thread(thread_add, ht, 0, 9);
t[1] = thread(thread_add, ht, 10, 19);
t[0].join();
t[1].join();
std::cout << "size: " << ht.size() << std::endl;
}
int main()
{
test();
return 0;
}
However, there are errors when compiling it.
但是,编译时会出错。
$ g++ -std=c++11 -pthread test.cpp
...
/usr/include/c++/4.8.2/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<void (*(std::unordered_map<int, int>, int, int))(std::unordered_map<int, int>&, int, int)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
...
Took a while but still cannot correct it. Thanks.
花了一段时间,但仍然无法纠正它。谢谢。
2 个解决方案
#1
31
I could compile your code successfully with MSVC2013. However, thread()
works passing copies of its argument to the new thread. This means that if your code would compile on your compiler, each thread wourd run with its own copy of ht
, so that at the end, main
's ht
would be empty.
我可以使用MSVC2013成功编译您的代码。但是,thread()可以将其参数的副本传递给新线程。这意味着如果您的代码将在您的编译器上编译,则每个线程都使用自己的ht副本运行,因此最后,main的ht将为空。
GCC doesn't compile with this weird message. You can get rid of it by using the reference wraper with thread:
GCC不会使用这个奇怪的消息进行编译。你可以通过使用带线程的引用包装器来摆脱它:
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
This will compile succesfully. And each reference used by the threads would refer to the same object.
这将成功编译。并且线程使用的每个引用都将引用相同的对象。
However, there are high chances that you'll get some runtime error or unexpected results. This is because two threads are concurently trying to insert into ht
. But unordered_map
is not thread safe, so these racing conditions might cause ht
to reach an unstable state (i.e. UB, i.e. potential segfault).
但是,很有可能会出现运行时错误或意外结果。这是因为两个线程正在尝试插入ht。但unordered_map不是线程安全的,因此这些竞争条件可能导致ht达到不稳定状态(即UB,即潜在的segfault)。
To make it running properly, you have to protect your concurent accesses:
为了使其正常运行,您必须保护您的concurent访问:
#include <mutex>
...
mutex mtx; // to protect against concurent access
void thread_add(unordered_map<int, int>& ht, int from, int to)
{
for (int i = from; i <= to; ++i) {
std::lock_guard<std::mutex> lck(mtx); // protect statements until end of block agains concurent access
ht.insert(unordered_map<int, int>::value_type(i, 0));
}
}
#2
21
The error is very cryptic indeed, but the problem is that thread_add
takes its first parameter by reference, but you're passing it by value. This causes the functor type to be deduced wrong. If you want to pass something actually by reference to a functor like std::bind
or the main function of a std::thread
, you need to use a reference wrapper (std::ref
):
这个错误确实很神秘,但问题是thread_add通过引用获取它的第一个参数,但是你按值传递它。这会导致仿函数类型推断错误。如果你想通过引用传递一些东西,比如std :: bind或std :: thread的main函数,你需要使用一个引用包装器(std :: ref):
void test()
{
// ...
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
// ...
}
[实例]
#1
31
I could compile your code successfully with MSVC2013. However, thread()
works passing copies of its argument to the new thread. This means that if your code would compile on your compiler, each thread wourd run with its own copy of ht
, so that at the end, main
's ht
would be empty.
我可以使用MSVC2013成功编译您的代码。但是,thread()可以将其参数的副本传递给新线程。这意味着如果您的代码将在您的编译器上编译,则每个线程都使用自己的ht副本运行,因此最后,main的ht将为空。
GCC doesn't compile with this weird message. You can get rid of it by using the reference wraper with thread:
GCC不会使用这个奇怪的消息进行编译。你可以通过使用带线程的引用包装器来摆脱它:
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
This will compile succesfully. And each reference used by the threads would refer to the same object.
这将成功编译。并且线程使用的每个引用都将引用相同的对象。
However, there are high chances that you'll get some runtime error or unexpected results. This is because two threads are concurently trying to insert into ht
. But unordered_map
is not thread safe, so these racing conditions might cause ht
to reach an unstable state (i.e. UB, i.e. potential segfault).
但是,很有可能会出现运行时错误或意外结果。这是因为两个线程正在尝试插入ht。但unordered_map不是线程安全的,因此这些竞争条件可能导致ht达到不稳定状态(即UB,即潜在的segfault)。
To make it running properly, you have to protect your concurent accesses:
为了使其正常运行,您必须保护您的concurent访问:
#include <mutex>
...
mutex mtx; // to protect against concurent access
void thread_add(unordered_map<int, int>& ht, int from, int to)
{
for (int i = from; i <= to; ++i) {
std::lock_guard<std::mutex> lck(mtx); // protect statements until end of block agains concurent access
ht.insert(unordered_map<int, int>::value_type(i, 0));
}
}
#2
21
The error is very cryptic indeed, but the problem is that thread_add
takes its first parameter by reference, but you're passing it by value. This causes the functor type to be deduced wrong. If you want to pass something actually by reference to a functor like std::bind
or the main function of a std::thread
, you need to use a reference wrapper (std::ref
):
这个错误确实很神秘,但问题是thread_add通过引用获取它的第一个参数,但是你按值传递它。这会导致仿函数类型推断错误。如果你想通过引用传递一些东西,比如std :: bind或std :: thread的main函数,你需要使用一个引用包装器(std :: ref):
void test()
{
// ...
t[0] = thread(thread_add, std::ref(ht), 0, 9);
t[1] = thread(thread_add, std::ref(ht), 10, 19);
// ...
}
[实例]