以这些为例
struct MyObj {
void * x;
int counter;
};
std::atomic<MyObj *> globalSourceThatGetsChangedByOtherThreads = ...;
这就是我想做的事情:
void someCode() {
//begin atomic
MyObj *dest = globalSourceThatGetsChangedByOtherThreads.load();
globalSourceThatGetsChangedByOtherThreads->counter++;
//end atomic
}
我试图通过x86汇编程序调用很聪明,但那不起作用。
答案 0 :(得分:1)
我不知道如何使用c11原子,但我认为你的意思是这样的。我一直使用联合来使用原子比较和交换来更改多个字段。使用指针时的另一种技术是利用操作系统实际使用的地址空间。 Windows 64位仅使用44位地址,并且是8字节对齐,这意味着您只需要41位来保存指针。这为计数器和其他字段释放了23位。这里我假设64位寻址,但您只需要48位地址空间。这为计数器释放了16位:
typedef unsigned int64 QWORD;
union {
// This struct is what we actually work with
struct {
QWORD m_x : 48, // most os don't use the full 64 bit address space...
m_c : 16;
};
// This is what we compare and swap.
QWORD m_n64;
// constructor to make the code clean. This doesn't use memory barriers
// so depending on your architecture, you might need a barrier. With x64 and
// windows the barrier on the compare and swap has always been sufficient.
MyObj(const volatile MyObj &r) volatile { m_n64 = r.m_n64; }
} MyObj;
while (1) {
// its not clear to me if pOld will change or the data at pOld or both, so i
// put volatile on both
volatile MyObj* volatile pOld = globalSourceThatGetsChangedByOtherThreads.load();
MyObj Old(*pOld), New(Old);
// set lots of fields!
New.m_x = (QWORD)somepointer;
New.m_c++;
// assume CompareAndSwap64 returns true if the 64 bit number was successfully swapped
if (CompareAndSwap64(pOld, &Old, &New))
break;
// if we get here, rare, we had a race. Try again.
}
答案 1 :(得分:0)
我认为这会奏效。
struct MyObj {
void * x;
std::atomic_int counter;
};
std::atomic<MyObj *> globalSourceThatGetsChangedByOtherThreads = ...;
void someCode() {
MyObj *dest;
while (true) {
dest = globalSourceThatGetsChangedByOtherThreads.load();
//globalSourceThatGetsChangedByOtherThreads could have changed between above and below
dest->counter++;
// check
if (dest == globalSourceThatGetsChangedByOtherThreads.load())
break;
else
dest->counter--;
}
dest->x->doSomethingReadOnly();
dest->counter--;
}