Atomic指令是什么意思?
以下内容如何成为Atomic?
检查并设置
int TestAndSet(int *x){
register int temp = *x;
*x = 1;
return temp;
}
Run Code Online (Sandbox Code Playgroud)
从软件的角度来看,如果不想使用非阻塞同步原语,那么如何确保指令的原子性?是否只能在硬件或某些装配级指令优化中使用?
language-agnostic synchronization test-and-set nonblocking atomicity
我将创建一个必须是原子的"long"(Int64)代理,因此它在并发应用程序中的副本本质上是安全的.我不能使用Int32,因为它的范围太短.
我知道,只要涉及的数据可以适合双字(32位),原子性就应该得到保证.无论操作系统是32位还是64位.
现在,考虑以下"长"代理人......
注意:我省略了几种方法,因为我不需要它们.在这种情况下,我只需要基本转换为/从真正的长.
public struct SafeLong
: IConvertible
{
public SafeLong(long value)
{
unchecked
{
var arg = (ulong)value;
this._data = new byte[]
{
(byte)arg,
(byte)(arg >> 8),
(byte)(arg >> 16),
(byte)(arg >> 24),
(byte)(arg >> 32),
(byte)(arg >> 40),
(byte)(arg >> 48),
(byte)(arg >> 56),
};
}
}
private byte[] _data;
private long Value
{
get
{
unchecked
{
var lo =
this._data[0] |
this._data[1] << 8 |
this._data[2] << 16 |
this._data[3] << 24;
var hi = …Run Code Online (Sandbox Code Playgroud) 我在我的多线程代码中使用incrementAndGet方法AtomicLong来衡量我们的一些客户端代码的性能.
@Override
public void run() {
long start = System.nanoTime();
attributes = client.getAttributes(columnsList);
long end = System.nanoTime() - start;
final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
if (before != null) {
before.incrementAndGet();
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我试图测量多少时间 -
client.getAttributes(columnsList);
正在服用.
据我所知,incrementAndGet方法将以原子方式将当前值增加1.这意味着每个线程可能会等待其他线程递增值.我对吗?意味着它会被封锁?
这也会影响我测量任何方法性能的方式吗?这意味着它会为该测量增加一些额外的时间吗?
为什么我要问这是因为我试图对大部分客户端代码和服务器端代码进行基准测试,如果我需要测量每种方法花费多少时间,那么我这样做就像这样 -
无论我想测量什么代码,我通常将下面的行放在该方法之上
long start = System.nanoTime();
而这两条线路采用相同的方法但却有所不同 ConcurrentHashMap
long end = System.nanoTime() - start;
final AtomicLong before = select.putIfAbsent(end / 1000000L, new AtomicLong(1L));
if (before != null) {
before.incrementAndGet(); …Run Code Online (Sandbox Code Playgroud) 我有一个HBase(v0.94.7)表,其中包含一个列族,并且随着时间的推移会添加列.这些列被命名为它们创建的时间戳,因此除非我查询该行,否则我不知道它具有的所有列.
现在给定一行,我想原子地删除此列族的所有现有列,并添加一组新的列和值.
所以我想到使用HBase的RowMutations,如:
RowMutations mutations = new RowMutations(row);
//delete the column family
Delete delete = new Delete(row);
delete.deleteFamily(cf);
//add new columns
Put put = new Put(row);
put.add(cf, col1, v1);
put.add(cf, col2, v2);
//delete column family and add new columns to same family
mutations.add(delete);
mutations.add(put);
table.mutateRow(mutations);
Run Code Online (Sandbox Code Playgroud)
但是这段代码最终做的只是删除列族,它不会添加新列.这种行为有望吗?
如果是这样,那么我如何实现我的目标,即用一组新的列原子替换列族的所有列?
以下是相同的测试用例:
import junit.framework.Assert;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableExistsException;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.NavigableMap;
public class …Run Code Online (Sandbox Code Playgroud) 为什么AtomicInteger同时具有int get()和int intValue()?我看到它还有来自Number的float floatValue().是否有一个与维持AtomicInteger参数的原子性相关的含义,或者是否可以互换?
使用Redis,我想执行一个原子序列的命令,即我需要保证在执行序列时没有其他客户端会在数据库中执行更改.
如果我只使用write命令,我可以使用MULTI和EXEC语句来确保使用事务的原子性.但是,我还想在我的事务中使用read命令.因此我无法使用MULTI,因为读命令也在排队!
基本上,以原子方式,我需要做以下事情:
x从数据库中读取,x,存储f(x)到数据库.1.和2.都应该是单个原子事务的一部分.
有一个简单的方法怎么做?
我从threads::shared描述中读到:
默认情况下,变量对每个线程都是私有的,每个新创建的线程都会获得每个现有变量的私有副本.此模块允许您跨不同的线程共享变量... (更多)
假设我有一个像这样的共享变量:
my $var :shared;
$var = 10;
Run Code Online (Sandbox Code Playgroud)
这意味着变量仅对我创建的所有线程存在一次.
现在关于原子性和可见性:
如果thread_A分配了一个新值,那么就说11:
$var = 11;
Run Code Online (Sandbox Code Playgroud)
是否保证thread_B(以及我可能创建的所有其他线程)都会看到值11?分配是原子地执行的吗?
或者我们是否首先在Java中获取锁定,然后执行赋值并释放锁定.并且只有使用相同锁的线程才能保证看到更新后的值?
或者这表现得像Java中的volatile原始变量?
考虑一个架构:
var userSchema = mongoose.Schema({
...
followers: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }],
following: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }]
...
}
Run Code Online (Sandbox Code Playgroud)
当userA下面userB,userB是被推动userA.following而userA在被推动userB.followers.这两项操作都需要.save().
什么是好方法 - 也许是概念性的 - 确保如果其中一个.save()失败,两个文件都保持不变?
假设我们有一个简单的变量(std::atomic<int> var)和2个线程T1,T2并且我们有以下代码T1:
...
var.store(2, mem_order);
...
Run Code Online (Sandbox Code Playgroud)
并为 T2
...
var.load(mem_order)
...
Run Code Online (Sandbox Code Playgroud)
另外,我们假设T2(load)执行时间晚于123ns (在C++标准的修改顺序中稍后),而不是T1(store).我对这种情况的理解如下(针对不同的内存顺序):
memory_order_seq_cst - T2负载必须加载2.因此,它必须加载最新的值(就像RMW操作的情况一样)memory_order_acquire/ memory_order_release/ memory_order_relaxed- T2没有义务加载2但可以加载任何旧值,但唯一的限制是:该值不应该早于该线程加载的最新值.所以,例如var.load返回0.我的理解是对的吗?
UPDATE1:
如果我的推理错了,请提供C++标准中的文本证明.不仅仅是一些架构如何运作的理论推理.
我正在尝试了解使用RDTSC/RDTSCP测量时间时使用栅栏的正确方法.关于与此相关的SO的几个问题已经得到了精心解答.我经历了其中一些.我也经历过关于同一主题的非常有用的文章:http: //www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-基准-代码执行-paper.pdf
但是,在另一个在线博客中,有一个在x86上使用LFENCE而不是CPUID的例子.我想知道LFENCE如何阻止早期商店污染RDTSC测量.例如
<Instr A>
LFENCE/CPUID
RDTSC
<Code to be benchmarked>
LFENCE/CPUID
RDTSC
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,LFENCE确保它之前完成的所有早期加载(因为SDM说:LFENCE指令不能通过先前的读取.).但是早期的商店呢(比如,Instr A是商店)?我理解为什么CPUID有效,因为它是一个序列化指令,但LFENCE不是.
我发现的一个解释是在英特尔SDM VOL 3A第8.3节中,以下脚注:
LFENCE确实为指令排序提供了一些保证.它在本地完成所有先前指令之前不会执行,并且在LFENCE完成之前不会再执行指令.
所以LFENCE本质上就像一个MFENCE.在那种情况下,为什么我们需要两个单独的指令LFENCE和MFENCE?
我可能错过了一些东西.
提前致谢.
atomicity ×10
java ×3
assembly ×1
atomic ×1
atomic-long ×1
c# ×1
c++ ×1
hbase ×1
mongoose ×1
node.js ×1
nonblocking ×1
perl ×1
redis ×1
test-and-set ×1
transactions ×1
visibility ×1
x86-64 ×1