【发布时间】:2016-10-29 21:43:51
【问题描述】:
我必须先为我糟糕的英语道歉。 我现在正在学习硬件事务内存,我正在使用 TBB 中的 spin_rw_mutex.h 在 C++ 中实现事务块。 speculative_spin_rw_mutex是spin_rw_mutex中的一个类。h是一个互斥体,已经实现了intel TSX的RTM接口。
我用来测试RTM的例子很简单。我创建了 Account 类,并随机将资金从一个帐户转移到另一个帐户。所有帐户都在一个帐户数组中,大小为100。随机函数在boost中。(我认为STL具有相同的随机函数)。传递函数受 speculative_spin_rw_mutex 保护。我使用 tbb::parallel_for 和 tbb::task_scheduler_init 来控制并发。所有传输方法都在 paraller_for 的 lambda 中调用。总传输次数为 100 万次。奇怪的是,当 task_scheduler_init 设置为 2 时,程序是最快的(8 秒)。事实上,我的 CPU 是 i7 6700k,它有 8 个线程。在 8 到 50,000 的范围内,程序的性能几乎没有变化(11 到 12 秒)。当我将 task_scheduler_init 增加到 100,000 时,运行时间将增加到大约 18 秒。 我尝试使用分析器分析程序,发现热点函数是互斥锁。但是我认为事务回滚率并没有那么高。不知道为什么程序这么慢。
有人说虚假分享会降低性能,结果我尝试使用
std::vector> cache_aligned_accounts(AccountsSIZE,Account(1000));
替换原来的数组
账户* 账户[AccountsSIZE];
避免虚假分享。似乎没有任何改变; 这是我的新代码。
#include <tbb/spin_rw_mutex.h>
#include <iostream>
#include "tbb/task_scheduler_init.h"
#include "tbb/task.h"
#include "boost/random.hpp"
#include <ctime>
#include <tbb/parallel_for.h>
#include <tbb/spin_mutex.h>
#include <tbb/cache_aligned_allocator.h>
#include <vector>
using namespace tbb;
tbb::speculative_spin_rw_mutex mu;
class Account {
private:
int balance;
public:
Account(int ba) {
balance = ba;
}
int getBalance() {
return balance;
}
void setBalance(int ba) {
balance = ba;
}
};
//Transfer function. Using speculative_spin_mutex to set critical section
void transfer(Account &from, Account &to, int amount) {
speculative_spin_rw_mutex::scoped_lock lock(mu);
if ((from.getBalance())<amount)
{
throw std::invalid_argument("Illegal amount!");
}
else {
from.setBalance((from.getBalance()) - amount);
to.setBalance((to.getBalance()) + amount);
}
}
const int AccountsSIZE = 100;
//Random number generater and distributer
boost::random::mt19937 gener(time(0));
boost::random::uniform_int_distribution<> distIndex(0, AccountsSIZE - 1);
boost::random::uniform_int_distribution<> distAmount(1, 1000);
/*
Function of transfer money
*/
void all_transfer_task() {
task_scheduler_init init(10000);//Set the number of tasks can be run together
/*
Initial accounts, using cache_aligned_allocator to avoid false sharing
*/
std::vector<Account, cache_aligned_allocator<Account>> cache_aligned_accounts(AccountsSIZE,Account(1000));
const int TransferTIMES = 10000000;
//All transfer tasks
parallel_for(0, TransferTIMES, 1, [&](int i) {
try {
transfer(cache_aligned_accounts[distIndex(gener)], cache_aligned_accounts[distIndex(gener)], distAmount(gener));
}
catch (const std::exception& e)
{
//cerr << e.what() << endl;
}
//std::cout << distIndex(gener) << std::endl;
});
std::cout << cache_aligned_accounts[0].getBalance() << std::endl;
int total_balance = 0;
for (size_t i = 0; i < AccountsSIZE; i++)
{
total_balance += (cache_aligned_accounts[i].getBalance());
}
std::cout << total_balance << std::endl;
}
【问题讨论】:
-
这可能取决于您的操作系统架构实际可用的 CPU 内核数量。
-
我的 CPU 是 i7 6700k。 2个线程甚至比物理核心数还要少。
-
如前所述,“虚假共享”可能会产生影响。此外,如果您并行执行的工作被同步开销所掩盖,那么这可能会伤害您。与 2 个线程相比,具有 8 个线程的操作系统也有额外的调度开销。
-
记住操作系统必须调度线程。他们不单独运作。所以每个线程都有开销。
标签: c++ multithreading tbb intel-tsx