- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试实现一个无锁堆栈,以便与来自有界普通 c 数组的外部托管内存一起使用。我知道引用实现(例如 Anthony Williams:Concurrency in Action)以及网络上的其他书籍和博客/文章。
实现遵循这些引用并避免了 ABA 问题,因为外部内存位置是使用唯一索引而不是循环指针寻址的。因此它根本不需要处理内存管理并且很简单。
我编写了一些测试,在高负载和争用(压力测试)和单线程下对该堆栈执行弹出和推送操作。前者因奇怪的问题而失败,我不理解并且对我来说看起来很晦涩。
也许有人有想法?
问题:将已弹出的节点推回堆栈失败,因为违反了前提条件,即节点没有后继者(下一个)。
BOOST_ASSERT(!m_aData.m_aNodes[nNode-1].next);
复制设置:至少 3 个线程和 ~16 的容量。大约500次通过。然后推送操作失败。
问题:所有线程弹出的元素数量和加入后留在堆栈中的元素数量与容量不匹配(节点在转换中丢失)。
BOOST_ASSERT(aNodes.size()+nPopped == nCapacity);
复制设置:2 个线程和 2 个容量。需要很多遍才能发生,对我来说至少 700 个。在那之后堆栈头为 0,但弹出的容器中只存在一个节点。节点 {2,0} 悬空。
我用 vs2005、vs2013 和 vs2015 编译。都有同样的问题(vs2005也是代码看起来像C++03的原因)。
这里是node+stack的基本代码
template <typename sizeT> struct node
{
sizeT cur; //!< construction invariant
atomic<sizeT> next;
atomic<sizeT> data;
explicit node() // invalid node
: cur(0), next(0), data(0)
{}
explicit node(sizeT const& nCur, sizeT const& nNext, sizeT const& nData)
: cur(nCur), next(nNext), data(nData)
{}
node& operator=(node const& rhs)
{
cur = rhs.cur;
next.store(rhs.next.load(memory_order_relaxed));
data.store(rhs.data.load(memory_order_relaxed));
return *this;
}
};
template <typename sizeT> struct stack
{
private:
static memory_order const relaxed = memory_order_relaxed;
atomic<sizeT> m_aHead;
public:
explicit stack(sizeT const& nHead) : m_aHead(nHead) {}
template <typename tagT, typename T, std::size_t N>
typename enable_if<is_same<tagT,Synchronized>,sizeT>::type
pop(T (&aNodes)[N])
{
sizeT nOldHead = m_aHead.load();
for(;;)
{
if(!nOldHead) return 0;
BOOST_ASSERT(nOldHead <= N);
T& aOldHead = aNodes[nOldHead-1];
sizeT const nNewHead = aOldHead.next.load(/*relaxed*/);
BOOST_ASSERT(nNewHead <= N);
sizeT const nExpected = nOldHead;
if(m_aHead.compare_exchange_weak(nOldHead,nNewHead
/*,std::memory_order_acquire,std::memory_order_relaxed*/))
{
BOOST_ASSERT(nExpected == nOldHead);
// <--- from here on aOldHead is thread local ---> //
aOldHead.next.store(0 /*,relaxed*/);
return nOldHead;
}
// TODO: add back-off strategy under contention (use loop var)
}
}
template <typename tagT, typename T, std::size_t N>
typename enable_if<is_same<tagT,Synchronized>,void>::type
push(T (&aNodes)[N], sizeT const& nNewHead)
{
#ifndef NDEBUG
{
BOOST_ASSERT(0 < nNewHead && nNewHead <= N);
sizeT const nNext = aNodes[nNewHead-1].next;
BOOST_ASSERT(!nNext);
}
#endif
sizeT nOldHead = m_aHead.load(/*relaxed*/);
for(;;)
{
aNodes[nNewHead-1].next.store(nOldHead /*,relaxed*/);
sizeT const nExpected = nOldHead;
BOOST_ASSERT(nOldHead <= N);
if(m_aHead.compare_exchange_weak(nOldHead,nNewHead
/*,std::memory_order_release,std::memory_order_relaxed*/))
{
BOOST_ASSERT(nExpected == nOldHead);
return;
}
// TODO: add back-off strategy under contention (use loop var)
}
}
};
还有相当嘈杂的测试课
class StackTest
{
private:
typedef boost::mpl::size_t<64> Capacity;
//typedef boost::uint_t<static_log2_ceil<Capacity::value>::value>::least size_type;
typedef std::size_t size_type;
static size_type const nCapacity = Capacity::value;
static size_type const nNodes = Capacity::value;
typedef node<size_type> Node;
typedef stack<size_type> Stack;
typedef mt19937 Twister;
typedef random::uniform_int_distribution<std::size_t> Distribution;
typedef variate_generator<Twister,Distribution> Die;
struct Data //!< shared along threads
{
Node m_aNodes[nNodes];
Stack m_aStack;
explicit Data() : m_aStack(nNodes)
{
m_aNodes[0] = Node(1,0,0); // tail of stack
for(size_type i=1; i<nNodes; ++i)
{
m_aNodes[i] = Node(static_cast<size_type>(i+1),i,0);
}
}
template <typename syncT>
void Run(
uuids::random_generator& aUUIDGen,
std::size_t const& nPasses,
std::size_t const& nThreads)
{
std::vector<ThreadLocalData> aThreadLocalDatas(nThreads,ThreadLocalData(*this));
{
static std::size_t const N = 100000;
Die aRepetition(Twister(hash_value(aUUIDGen())),Distribution(0,N));
Die aAction(Twister(hash_value(aUUIDGen())),Distribution(0,1));
for(std::size_t i=0; i<nThreads; ++i)
{
std::vector<bool>& aActions = aThreadLocalDatas[i].m_aActions;
std::size_t const nRepetition = aRepetition();
aActions.reserve(nRepetition);
for(std::size_t k=0; k<nRepetition; ++k)
{
aActions.push_back(static_cast<bool>(aAction()));
}
}
}
std::size_t nPopped = 0;
if(nThreads == 1)
{
std::size_t const i = 0;
aThreadLocalDatas[i].Run<syncT>(i);
nPopped += aThreadLocalDatas[i].m_aPopped.size();
}
else
{
std::vector<boost::shared_ptr<thread> > aThreads;
aThreads.reserve(nThreads);
for(std::size_t i=0; i<nThreads; ++i)
{
aThreads.push_back(boost::make_shared<thread>(boost::bind(&ThreadLocalData::Run<syncT>,&aThreadLocalDatas[i],i)));
}
for(std::size_t i=0; i<nThreads; ++i)
{
aThreads[i]->join();
nPopped += aThreadLocalDatas[i].m_aPopped.size();
}
}
std::vector<size_type> aNodes;
aNodes.reserve(nCapacity);
while(size_type const nNode = m_aStack.pop<syncT>(m_aNodes))
{
aNodes.push_back(nNode);
}
std::clog << dump(m_aNodes,4) << std::endl;
BOOST_ASSERT(aNodes.size()+nPopped == nCapacity);
}
};
struct ThreadLocalData //!< local to each thread
{
Data& m_aData; //!< shared along threads
std::vector<bool> m_aActions; //!< either pop or push
std::vector<size_type> m_aPopped; //!< popp'ed nodes
explicit ThreadLocalData(Data& aData)
: m_aData(aData), m_aActions(), m_aPopped()
{
m_aPopped.reserve(nNodes);
}
template <typename syncT>
void Run(std::size_t const& k)
{
BOOST_FOREACH(bool const& aAction, m_aActions)
{
if(aAction)
{
if(size_type const nNode = m_aData.m_aStack.pop<syncT>(m_aData.m_aNodes))
{
BOOST_ASSERT(!m_aData.m_aNodes[nNode-1].next);
m_aPopped.push_back(nNode);
}
}
else
{
if(!m_aPopped.empty())
{
size_type const nNode = m_aPopped.back();
size_type const nNext = m_aData.m_aNodes[nNode-1].next;
ASSERT_IF(!nNext,"nNext=" << nNext << " for " << m_aData.m_aNodes[nNode-1] << "\n\n" << dump(m_aData.m_aNodes));
m_aData.m_aStack.push<syncT>(m_aData.m_aNodes,nNode);
m_aPopped.pop_back();
}
}
}
}
};
template <typename syncT>
static void PushPop(
uuids::random_generator& aUUIDGen,
std::size_t const& nPasses,
std::size_t const& nThreads)
{
BOOST_ASSERT(nThreads > 0);
BOOST_ASSERT(nThreads == 1 || (is_same<syncT,Synchronized>::value));
std::clog << BOOST_CURRENT_FUNCTION << " with threads=" << nThreads << std::endl;
for(std::size_t nPass=0; nPass<nPasses; ++nPass)
{
std::ostringstream s;
s << " " << nPass << "/" << nPasses << ": ...";
std::clog << s.str() << std::endl;
Data().Run<syncT>(aUUIDGen,nPass,nThreads);
}
}
public:
static void Run()
{
typedef StackTest self_t;
uuids::random_generator aUUIDGen;
static std::size_t const nMaxPasses = 1000;
Die aPasses(Twister(hash_value(aUUIDGen())),Distribution(0,nMaxPasses));
{
//std::size_t const nThreads = 2; // thread::hardware_concurrency()+1;
std::size_t const nThreads = thread::hardware_concurrency()+1;
self_t().PushPop<Synchronized>(aUUIDGen,aPasses(),nThreads);
}
}
};
这是一个link下载所有需要的文件。
最佳答案
这两个问题只是 ABA 问题的另一个方面。
堆栈:{2,1},{1,0}
任何问题都可能出现,因为对节点的访问不再是线程本地的。这包括对弹出节点(问题 1)或丢失节点(问题 2)的下一个意外修改。
head+next 需要在一个cmp_exch 中修改以避免该问题。
关于C++ 无锁堆栈已损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37746576/
循环不起作用,我想就是这样,也许 list[i].removeChild(list[i]);我想删除 lt 列表类。 function removeDone () { var lista = do
我正在制作一个java程序,它能够使用他们的api将(主要是mp4)文件上传到主机openload.co,你可以找到here . 我的程序可以上传 mp4 视频,但无法播放。当我下载以前上传的视频并通
我在服务器端使用 jquery-file-upload 和 Python-Flask。每当我上传 100mb 以上的大文件时,上传的版本比原始版本稍大并且无法打开(已损坏)。我对 10mb block
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭10 年前。 Improve th
我有一个按钮,它是我的 Magento 主题中提供的代码的一部分,根据日期/时间戳,我没有无意中编辑它。我确信它在某些时候是有效的,但回顾一下上周我的源代码控制,我似乎无法找出哪里出了问题。 这是按钮
我有一个将一些数据写入新文件的简单函数。它可以工作,并且文件已写入,但在 MSVS Express 2013 中调试时出现上述错误。 void writeSpecToFile(const char *
我试图包含我的应用程序的国际化,并且仅出于测试目的,我在文件 Localized.string 中添加了一行简单的代码。 这是我的整个文件: "Test locale" = "Test locale"
这是代码: console.log(234, document.links); console.log(235, document.links.length); 输出显示数组中有值,但返回 0。 这是
我在尝试使用 ASP.NET MVC3 的 Ajax.BeginForm 方法时遇到了一个奇怪的问题。表单通过正确的操作属性在页面上正确呈现。但是,当提交表单时,“OnFailure”事件返回“Not
我是 10 年级的学生,我在 APCS 的最终项目是制作一个游戏/应用程序并提交代码、运行视频和书面回复。我的问题是整个类(class)都是使用 Code.org 的 AppLab 进行教学的,并且
我正在使用带有 Microsoft auth 的 azure webapp。几个月来一直工作良好。 然而今天它坏了。login.microsoftonline.com 页面因 css 和 js 加载错
我遇到了一个奇怪的问题。直到几分钟前才出现问题。在不对 less/css 文件进行任何更改的情况下(从不),引导按钮和导航栏标题的外观突然发生了变化。在第一张图片上,您可以看到按钮应该是什么样子,在第
我正在开发一个用于核心转储处理的工具。使用 sysctl 我将其设置为获取工具输入的核心转储。一切都运转良好。但今天我面临着(我不知道为什么)coredump 损坏的情况。当我将常规文件设置为核心转储
我对一个我继承但并非最初创建的网站感到非常头疼。几乎所有的样式都是通过一个样式表完成的。问题是自动调整大小不再有效,所有页面现在都以指定的最小宽度显示。随着时间的推移,各种不同的人添加了它,CSS 变
我正在尝试使用 AngularJS 甚至纯 JavaScript 将 HTML 表格转换为 XLSX。 当我使用下面的方法转换为 XLS 时,它的下载正常并且 XLS 文件正在打开。 var blob
需要根帮助导致 vtable 损坏问题(不确定这是否正在发生)。这是代码的非常简化的版本。 class CBase { public: CBase() virtual ~CBase()
一段时间未在 Play 商店中更新我的应用程序后,我尝试使用我的 keystore 对我的一个 APK 进行签名,结果发现 keystore 和别名密码不再起作用。我可以使用此要点重置的 keysto
已安装 XCode 6在 Mavericks .它不运行。将操作系统更新为 Yosemite 10.10 :现在 Xcode.app(通过 *.dmg 安装)启动失败并显示错误消息 “Xcode” i
我有一个在我的应用程序中使用的 plist 文件,我可以对其进行本地化,因此我在我的项目中得到两个条目,一个用于英语,一个用于西类牙语,当我编译运行该应用程序时,它可以工作,但当然在这个阶段内容是相同
我相信这是来自 androidsnippets.org 的 fragment - 为什么它在 Android 2.3 上不起作用?如何解决? 错误 03-05 23:19:17.479: WARN/S
我是一名优秀的程序员,十分优秀!