虽然标准不保证new
的线程安全,但大多数多线程操作系统support thread-safe operator new
。
我正在实现自己的内存管理,以便在我的代码中动态分配某些class
(比如MyClass
)。对于MyClass
的线程安全性,我可能必须使用pthread
或boost::
库。
我认为如果new
已经线程安全,那么我可以为MyClass
重载它并利用其安全性而不必担心使用这些库。
class MyClass {
// data
public:
void* operator new (size_t);
void operator delete (void*);
};
对C ++ 03系统/编译器来说这是一个公平的假设吗?
修改:由于我的问题没有被少数用户所遵循。我正在详细说明那部分:
如果我有2个执行new int()
和new int()
的线程,则会返回2个唯一的内存地址。现在,在我的重载MyClass::new
中,我没有使用全局::new()
或任何线程库;但是自己的内存管理器(它对线程一无所知)。伪代码:
char pool[BIG_SIZE];
void* MyClass::operator new (size_t size)
{
// get some memory from 'pool' without using any thread library
return p;
}
我的假设是,由于全局::new
是线程安全的,因此这个重载的operator new
也应该是线程安全的。换句话说,编译器应该在遇到new
关键字的任何地方发出与线程安全相关的代码。这是正确的假设吗?
答案 0 :(得分:3)
是的。
但请注意,在C ++ 11中,new是线程安全的。
当然,当你添加线程不安全的代码时,它会使你的operator new
线程不安全。
编辑后(改变了整个问题):
假设编译器在新调用中添加了线程安全代码 是非常错误的。 Sane实现将始终在operator new的内部实现中添加线程安全性(已经因为每线程内存池等效率考虑因素)。
也就是说,当你编写一个线程不安全的分配函数时,只需命名它operator new
就不会神奇地使它成为线程安全的,因为这就像任何其他函数一样,只能用一种特殊的方式来调用。
答案 1 :(得分:2)
我认为对于您编辑过的问题,答案肯定是“不”。
您似乎也对新运算符和新表达式感到困惑(没有::new()
这样的东西,只有::new
和::operator new()
),所以也许最好将其分解
当你写T * p = new T;
时,T
有一个重载的operator-new,那么就会发生一个等同于下面的序列:
void * addr = T::operator new(sizeof(T)); // #1
::new (addr) T; // global placement-new
#1中的函数调用才是最重要的。这个调用是否是线程安全的?那么,这完全取决于你如何定义该功能!标准中有 nothing 可以保证该函数的任何特定行为,这毕竟是一个完全普通的函数。
(新)标准或编译器供应商唯一保证的是默认提供的全局函数void * ::operator new(std::size_t) throw(std::bad_alloc);
是线程安全的。所以如果你使用那个编写自己的函数,你就可以了;否则你就是自己:
struct Foo
{
static void * operator new(size_t n) { return ::operator new(n); } // OK
};
struct Bar
{
static void * operator new(size_t n) { horribly_broken_function(); return 0x0505; }
// probably not OK
}
答案 2 :(得分:0)
来自更新的问题:
我的假设是,因为global :: new是线程安全的,所以这个重载的operator new也应该是线程安全的。换句话说,编译器应该在遇到新关键字的任何地方发出与线程安全相关的代码。这是正确的假设吗?
没有。
或者,从某种意义上讲,它对编译器生成的所有代码都很重要,即不允许编译器引入原始源代码中不存在的数据竞争(原则上,以前的措辞是在C ++ 11内存模型中找到,但实际上支持线程的C ++ 98编译器仍然遵循它,否则就不可能创建健壮的线程程序。)
IOW,编译器可以帮助您创建线程安全的代码,使其不会使您编写的线程安全的代码不安全。但是,它没有反过来;没有神奇的线程安全小精灵灰尘,编译器可以在你的线程不安全的代码上撒上它以使其线程安全。
具体说明另一种解释。运算符new通过“n.m”复制粘贴:
MyClass :: operator new只是一个常规函数,有些奇怪的语法。它与任何:: operator new变量无关,也不会神奇地继承它们的线程安全性
或“Kerrek SB”中的相同内容:
比如上午上面,我没有按照您的问题 - 重载运算符只是一个完全普通的(静态)成员函数。这与你做的一样好或坏!如果运算符内部的内存获取使用:: operator new(n);,则该特定调用是线程安全的,并且您必须使其他所有内容都是线程安全的
说实话,我很难搞清楚这里还不清楚的事情......