我必须先为我糟糕的英语道歉。我现在正在学习硬件事务内存,我正在使用 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;
}