我正在建立一个网站,我想在标准的MyISAM表中增加一个计数器.
简化示例:
UPDATE votes SET num = num + 1;
Run Code Online (Sandbox Code Playgroud)
如果多个连接正在执行相同的查询,这会导致问题,还是MySQL会处理它并锁定表或某些东西以确保没有冲突?
我一直在阅读一篇关于MSDN中的无锁编程的文章.它说 :
在所有现代处理器上,您可以假设自然对齐的本机类型的读取和写入 是原子的.只要存储器总线至少与读取或写入的类型一样宽,CPU就会在单个总线事务中读取和写入这些类型,这使得其他线程无法在半完成状态下看到它们.
它给出了一些例子:
// This write is not atomic because it is not natively aligned.
DWORD* pData = (DWORD*)(pChar + 1);
*pData = 0;
// This is not atomic because it is three separate operations.
++g_globalCounter;
// This write is atomic.
g_alignedGlobal = 0;
// This read is atomic.
DWORD local = g_alignedGlobal;
Run Code Online (Sandbox Code Playgroud)
我读了很多答案和评论说,没有什么能保证在C++中是原子的,甚至在标准中都没有提到,在SO中,现在我有点困惑.我误解了这篇文章吗?或者文章作者是否谈论了非标准和特定于MSVC++编译器的内容?
所以根据这篇文章,下面的作业必须是原子的,对吧?
struct Data
{
char ID;
char pad1[3];
short Number;
char pad2[2];
char Name[5];
char pad3[3];
int Number2;
double …Run Code Online (Sandbox Code Playgroud) 我打算声明一个原子变量向量,用作多线程程序中的计数器.这是我尝试过的:
#include <atomic>
#include <vector>
int main(void)
{
std::vector<std::atomic<int>> v_a;
std::atomic<int> a_i(1);
v_a.push_back(a_i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是gcc 4.6.3的烦人冗长的错误信息:
In file included from /usr/include/c++/4.6/x86_64-linux-gnu/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.6/bits/allocator.h:48,
from /usr/include/c++/4.6/vector:62,
from test_atomic_vec.h:2,
from test_atomic_vec.cc:1:
/usr/include/c++/4.6/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(__gnu_cxx::new_allocator<_Tp>::pointer, const _Tp&) [with _Tp = std::atomic<int>, __gnu_cxx::new_allocator<_Tp>::pointer = std::atomic<int>*]’:
/usr/include/c++/4.6/bits/stl_vector.h:830:6: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = std::atomic<int>, _Alloc = std::allocator<std::atomic<int> >, std::vector<_Tp, _Alloc>::value_type = std::atomic<int>]’
test_atomic_vec.cc:10:20: instantiated from here
/usr/include/c++/4.6/ext/new_allocator.h:108:9: error: use of deleted function ‘std::atomic<int>::atomic(const std::atomic<int>&)’
/usr/include/c++/4.6/atomic:538:7: error: declared …Run Code Online (Sandbox Code Playgroud) 所有std::sync::atomic::AtomicBool采用内存排序的方法(Relaxed,Release,Acquire,AcqRel和SeqCst),我以前没用过.在什么情况下应该使用这些值?该文档使用令人困惑的"加载"和"存储"术语,我并不理解.例如:
生成器线程改变由a持有的某个状态Mutex,然后调用AtomicBool: compare_and_swap(false, true, ordering):(以合并失效),如果它交换,则将"无效"消息发布到并发队列(例如,mpsc或winapi PostMessage).消费者线程重置AtomicBool,从队列中读取,并读取互斥锁持有的状态.生产者是否可以使用轻松排序,因为它之前是互斥锁,或者必须使用Release?消费者可以使用store(false, Relaxed)或必须使用它compare_and_swap(true, false, Acquire)来接收来自互斥锁的更改吗?
如果生产者和消费者共享一个RefCell而不是一个Mutex?
就像是"修改"运营商+=,|=,&=等原子?
我知道++是原子的(如果你x++;同时在两个不同的线程中执行),你总是会x增加2,而不是x=x+1关闭优化.)
我想知道是否variable |= constant,以及喜欢是线程安全的还是我必须使用互斥锁来保护它们?
(...或者它是否依赖于CPU?在这种情况下,它在ARM上是怎么回事?)
我正在尝试理解c ++ 11中的内存防护,我知道有更好的方法可以做到这一点,原子变量等等,但是想知道这种用法是否正确.我意识到这个程序没有做任何有用的事情,我只是想确保fence功能的使用做了我认为他们做的事情.
基本上,该版本确保在围栏之前在此线程中所做的任何更改对于围栏之后的其他线程可见,并且在第二个线程中对变量的任何更改在围栏之后的线程中是否可见?
我的理解是否正确?或者我完全错过了这一点?
#include <iostream>
#include <atomic>
#include <thread>
int a;
void func1()
{
for(int i = 0; i < 1000000; ++i)
{
a = i;
// Ensure that changes to a to this point are visible to other threads
atomic_thread_fence(std::memory_order_release);
}
}
void func2()
{
for(int i = 0; i < 1000000; ++i)
{
// Ensure that this thread's view of a is up to date
atomic_thread_fence(std::memory_order_acquire);
std::cout << a;
}
}
int main()
{
std::thread t1 …Run Code Online (Sandbox Code Playgroud) 我想添加一个在Linux嵌入式系统上运行的服务(守护进程)使用的一些参数的网络控制.不需要过程调用,每个参数都可以以非常自然的方式进行轮询.共享内存似乎是一种很好的方法,可以将网络代码保留在守护程序之外,并限制对一组精心控制的变量的共享访问.
因为我不希望部分写入导致从未写过的值的可见性,所以我在考虑使用std::atomic<bool>和std::atomic<int>.但是,我担心这std::atomic<T>可能会以只适用于C++ 11线程而不是多个进程的方式实现(可能,甚至不包括OS线程).具体来说,如果实现使用存储在共享内存块之外的任何数据结构,则在多进程方案中,这将失败.
我确实看到一些要求,这些要求表明std::atomic不会存在嵌入式锁定对象或指向其他数据的指针:
原子积分专业化和专业化
atomic<bool>应具有标准布局.它们每个都有一个普通的默认构造函数和一个普通的析构函数.它们应各自支持聚合初始化语法.应该有原子类模板的指针部分特化.这些特化应具有标准布局,普通默认构造函数和普通析构函数.它们应各自支持聚合初始化语法.
在我看来,无关紧要的默认构造和破坏是排除关联的每个对象数据,无论是存储在对象内,还是通过指针成员变量,还是通过外部映射.
但是,我认为没有任何东西可以排除使用单个全局互斥/临界区(或者甚至是全局集合)的实现,只要集合元素不与单个原子对象相关联 - 这与缓存关联方案一致可用于减少虚假冲突).显然,使用全局互斥锁的实现对多个进程的访问会失败,因为用户将拥有独立的互斥锁,而不是实际上彼此同步.
是atomic<T>允许执行与进程间共享内存不兼容的实现,还是有其他规则使其安全?
我只是注意到,普通的默认构造使对象处于未就绪状态,并且需要调用atomic_init.标准提到了锁的初始化.如果这些存储在对象中(并且动态内存分配似乎不可能,因为析构函数仍然是微不足道的),那么它们将在进程之间共享.但我仍然担心全球互斥的可能性.
在任何情况下,保证atomic_init对共享区域中的每个变量进行单次调用似乎很难......所以我想我将不得不避开C++ 11原子类型.
当我正在阅读有关内存模型,障碍,排序,原子等等时,编译器栅栏的概念经常会出现,但通常情况下,它也会与CPU栅栏配对,正如人们所期望的那样.
但是,偶尔我会读到仅适用于编译器的fence构造.一个例子是C++ 11 std::atomic_signal_fence函数,它在cppreference.com上声明:
std :: atomic_signal_fence等效于std :: atomic_thread_fence,除了没有发出内存排序的CPU指令.仅按顺序指示抑制编译器对指令的重新排序.
我有五个与此主题相关的问题:
正如名称所暗示的那样std::atomic_signal_fence,是一个异步中断(例如一个被内核抢占以执行信号处理程序的线程)唯一一种只有编译器的栅栏才有用的情况?
它的用处是否适用于所有体系结构,包括强烈排序的体系结构x86?
是否可以提供一个特定的示例来演示仅编译器栅栏的用途?
使用时std::atomic_signal_fence,使用acq_rel和seq_cst订购之间有什么区别吗?(我希望它没有任何区别.)
这个问题可能是由第一个问题所覆盖,但我足够的好奇,一下也无妨具体问:是否曾经需要使用围栏与thread_local访问?(如果有的话,我希望只有编译器的围栏atomic_signal_fence才能成为首选工具.)
谢谢.
背景:
我维护了几个可以或已经从缓存中受益的Winforms应用程序和类库.我也知道缓存应用程序块和System.Web.Caching命名空间(根据我的收集,在ASP.NET之外使用它是完全可以的).
我发现,尽管上述两个类在技术上都是"线程安全的",因为单个方法是同步的,但它们似乎并没有真正适用于多线程方案.具体来说,它们没有实现类似于.NET 4.0中新类的GetOrAdd方法ConcurrentDictionary.
我认为这种方法是缓存/查找功能的原始方法,显然框架设计者也意识到了这一点 - 这就是为什么方法存在于并发集合中的原因.但是,除了我还没有在生产应用程序中使用.NET 4.0这一事实,字典不是一个完整的缓存 - 它没有像过期,持久/分布式存储等功能.
为什么这很重要:
"富客户端"应用程序(甚至是某些Web应用程序)中的一个相当典型的设计是在应用程序启动时立即开始预加载缓存,阻止客户端请求尚未加载的数据(随后将其缓存以备将来使用)使用).如果用户正在快速浏览他的工作流程,或者网络连接速度很慢,那么客户端与预加载器竞争并不常见,并且两次请求相同的数据真的没有多大意义. ,特别是如果请求相对昂贵.
所以我似乎留下了一些同样糟糕的选择:
不要试图使操作成为原子,并冒着两次加载数据的风险(并且可能有两个不同的线程在不同的副本上运行);
序列化对缓存的访问,这意味着锁定整个缓存只是为了加载单个项目 ;
开始重新发明轮子只是为了获得一些额外的方法.
澄清:示例时间表
假设当应用程序启动时,它需要加载3个数据集,每个数据集需要10秒才能加载.请考虑以下两个时间表:
00:00 - Start loading Dataset 1 00:10 - Start loading Dataset 2 00:19 - User asks for Dataset 2
在上面的例子中,如果我们不使用任何类型的同步,用户必须等待整整10秒才能获得1秒内可用的数据,因为代码将看到该项目尚未加载到缓存中并尝试重新加载它.
00:00 - Start loading Dataset 1 00:10 - Start loading Dataset 2 00:11 - User asks for Dataset 1
在这种情况下,用户要求已经在缓存中的数据.但是如果我们序列化对缓存的访问,他将不得不等待另外9秒,因为缓存管理器(无论是什么)都不知道要求的特定项目,只有那个"东西"是被要求和"某事"正在进行中.
问题: …
我使用C++ std::atomic_flag作为原子布尔标志.将标志设置为true或false不是问题,但如何查询标志的当前状态而不将其设置为某个值?我知道有方法' atomic_flag_clear'和' atomic_flag_set'.他们确实回馈了以前的状态,但也修改了当前的状态.有没有办法在不修改它的情况下查询标志状态,或者我是否必须使用完全成熟的' std::atomic<bool>'.