我正在研究一个需要广泛的C API互操作的系统.部分互操作需要在任何操作之前和之后初始化和关闭相关系统.如果不这样做将导致系统不稳定.我通过简单地在核心一次性环境类中实现引用计数来实现这一点,如下所示:
public FooEnvironment()
{
lock(EnvironmentLock)
{
if(_initCount == 0)
{
Init(); // global startup
}
_initCount++;
}
}
private void Dispose(bool disposing)
{
if(_disposed)
return;
if(disposing)
{
lock(EnvironmentLock)
{
_initCount--;
if(_initCount == 0)
{
Term(); // global termination
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这很好,并完成了目标.但是,由于任何互操作操作必须使用块嵌套在FooEnvironment中,因此我们始终锁定并且分析表明此锁定占运行时期间完成工作的近50%.在我看来,这是一个基本的概念,.NET或CLR中的某些东西必须解决它.有没有更好的方法来进行引用计数?
看这个例子:
#include <iostream>
#include <memory>
class Foo {
public:
Foo() { std::cout << "Foo()\n"; }
~Foo() { std::cout << "~Foo()\n"; }
};
int main(){
auto deleter = [](Foo* p) {
if(!p) { std::cout << "Calling deleter on nullptr\n"; }
delete p;
};
std::shared_ptr<Foo> foo;
std::cout << "\nWith non-null Foo:\n";
foo = std::shared_ptr<Foo>(new Foo, deleter);
std::cout << "foo is " << (foo ? "not ":"") << "null\n";
std::cout << "use count=" << foo.use_count() << '\n';
foo.reset();
std::cout << "\nWith nullptr and …Run Code Online (Sandbox Code Playgroud) 我想了解为什么以下似乎在 Rust 中无法正常工作。
我想对一个向量进行分块,并给每个线程一个块来处理它。我尝试使用 Arc 和 Mutex 组合来相互访问我的 vec。
这是我的第一次(明显的)尝试:声明 vec,将其分块,将块发送到每个线程中。根据我的理解,它应该有效,因为 Chunk 方法保证不重叠的块。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(vec![0;20]));
let chunk_size = 5;
let mut threads = vec![];
let chunks: Vec<&mut [u8]> = data.lock().unwrap().chunks_mut(chunk_size).collect();
for chunk in chunks.into_iter(){
threads.push(thread::spawn(move || {
inside_thread(chunk)
}));
}
}
fn inside_thread(chunk: &mut [u8]) {
// now do something with chunk
}
Run Code Online (Sandbox Code Playgroud)
该错误表明数据不够活跃。愚蠢的我,通过分块,我创建了指向数组的指针,但没有将 Arc 引用传递到线程中。所以我改变了几行,但这没有意义,因为我的线程中有一个未使用的引用!?
for i in 0..data.lock().unwrap().len() / 5 {
let ref_to_data = data.clone();
threads.push(thread::spawn(move || { …Run Code Online (Sandbox Code Playgroud) 假设您在共享内存中有一个引用计数对象.引用计数表示使用该对象的进程数,进程负责通过原子指令递增和递减计数,因此引用计数本身也在共享内存中(它可以是对象的字段,也可以是对象可以包含指向计数的指针,如果他们协助解决这个问题,我愿意接受建议.有时,进程会有一个错误,阻止它减少计数.如何让它尽可能简单地确定哪个过程不会减少计数?
我想到的一个解决方案是给每个进程一个UID(可能是他们的PID).然后当进程递减时,他们将UID推送到与引用计数一起存储的链表上(我选择了一个链表,因为你可以原子地附加到CAS的头部).当您想要调试时,您有一个特殊的进程,它查看共享内存中仍然存在的对象的链接列表,并且列表中没有的任何应用程序的UID是尚未减少计数的那些.
该解决方案的缺点在于它具有O(N)存储器使用,其中N是进程的数量.如果使用共享内存区域的进程数很大,并且您有大量对象,则这很快就会变得非常昂贵.我怀疑有可能是一个中间解决方案,其中有部分固定大小的信息,您可以通过某种方式能够缩小可能的进程列表,即使你不能找出一个一协助调试.或者,如果你能发现它的过程还没有递减当只有一个单一的过程还没有(即无法处理2个或多个进程未能递减计数的检测),这将可能仍然是一个很大的帮助.
(这个问题有更多'人类'解决方案,比如确保所有应用程序使用相同的库来访问共享内存区域,但是如果共享区域被视为二进制接口,并且并非所有进程都是由你不能控制自己.而且,即使所有的应用程序使用相同的库,一个应用程序可能会在库外部出现一个破坏内存的错误,这样就不会减少计数.是的我正在使用不安全的语言C/C++;)
编辑:在单进程情况下,您将拥有控制权,因此您可以使用RAII(在C++中).
algorithm debugging multithreading reference-counting shared-memory
你好,
我有一些麻烦理解python引用计数.我想要做的是使用ctypes模块将元组从c ++返回到python.
C++:
PyObject* foo(...)
{
...
return Py_BuildValue("(s, s)", value1, value2);
}
Run Code Online (Sandbox Code Playgroud)
蟒蛇:
pointer = c_foo(...) # c_foo loaded with ctypes
obj = cast(pointer, py_object).value
Run Code Online (Sandbox Code Playgroud)
我不确定obj的引用计数,所以我试过sys.getrefcount()
了3.我认为它应该是2(getrefcount函数使一个ref本身).
现在我无法Py_DECREF()在C++中返回之前创建,因为该对象被删除了.我可以减少python中的引用计数吗?
编辑 调用强制转换函数时,引用计数会发生什么?我不太确定下面的文档.http://docs.python.org/library/ctypes.html#ctypes.cast
ctypes.cast(obj,type)此函数类似于C中的强制转换运算符.它返回一个新的类型实例,它指向与obj相同的内存块.type必须是指针类型,obj必须是可以解释为指针的对象.
我正在尝试使用时使用类型系统QSharedData.这个想法很简单,会有许多不同的数据类型,每个类型都将从基础抽象类派生.我想用它QSharedData来存储每一个中的实际数据,但是每个派生类都会在里面存储不同的数据.我现在正试图做出最基本的例子,并遇到一些麻烦.
假设这些是我的基本纯虚拟类:
class cAbstractData: public QSharedData
{
public:
cAbstractData(){ }
virtual int type() = 0;
};
class cAbstractValue
{
public:
cAbstractValue(){ }
virtual int type() = 0;
protected:
QSharedDataPointer<cAbstractData>data_;
};
Run Code Online (Sandbox Code Playgroud)
现在让我们说我想创建一个表示单个值的类(作为一个简单的例子).我cAtomicValue从基值类派生,我也派生一个数据类来保存值:
class cAtomicData:public cAbstractData
{
public:
cAtomicData() { value_ = 0; }
int type(){ return 1; }
QVariant value_;//the actual value
};
class cAtomicValue:public cAbstractValue
{
public:
cAtomicValue() {
data_ = new cAtomicData;//creating the data object.
}
int type(){ return 1; }
};
Run Code Online (Sandbox Code Playgroud)
现在在这个阶段它工作得很好,在调试器中我可以看到正确的指针类型.但现在我想添加一个设置和获取值的函数,我不明白该怎么做.我们以制定者为例.要设置值,我们必须访问 …
给出以下(手动引用计数):
void (^block)(void) = ^ {
NSLog(@"wuttup");
}
void (^async_block)(void) = ^ {
block();
}
dispatch_async(dispatch_get_main_queue(), async_block);
Run Code Online (Sandbox Code Playgroud)
将"阻止"复制而不是从堆栈中抛出并销毁?
我已经读过创建或复制std :: shared_ptr涉及一些开销(参考计数器的原子增量等).
但是如何从它创建一个std :: weak_ptr:
Obj * obj = new Obj();
// fast
Obj * o = obj;
// slow
std::shared_ptr<Obj> a(o);
// slow
std::shared_ptr<Obj> b(a);
// slow ?
std::weak_ptr<Obj> c(b);
Run Code Online (Sandbox Code Playgroud)
我希望在一些更快的性能,但我知道共享指针仍然必须递增弱引用计数器..所以这仍然像将shared_ptr复制到另一个慢?
请看下面的代码:
#include <pthread.h>
#include <boost/atomic.hpp>
class ReferenceCounted {
public:
ReferenceCounted() : ref_count_(1) {}
void reserve() {
ref_count_.fetch_add(1, boost::memory_order_relaxed);
}
void release() {
if (ref_count_.fetch_sub(1, boost::memory_order_release) == 1) {
boost::atomic_thread_fence(boost::memory_order_acquire);
delete this;
}
}
private:
boost::atomic<int> ref_count_;
};
void* Thread1(void* x) {
static_cast<ReferenceCounted*>(x)->release();
return NULL;
}
void* Thread2(void* x) {
static_cast<ReferenceCounted*>(x)->release();
return NULL;
}
int main() {
ReferenceCounted* obj = new ReferenceCounted();
obj->reserve(); // for Thread1
obj->reserve(); // for Thread2
obj->release(); // for the main()
pthread_t t[2];
pthread_create(&t[0], NULL, Thread1, obj); …Run Code Online (Sandbox Code Playgroud) c++ multithreading boost reference-counting thread-sanitizer
情况:我的代码使用引用计数指针类(本质上类似,以提升::: intrusive_ptr)来管理其动态分配并避免内存泄漏。
AFAICT可以正常工作,并且不会泄漏内存;但是,当我在使用此类的代码上运行Clang静态分析器时,Clang似乎无法理解引用计数逻辑,因此会生成有关内存泄漏和释放后使用错误的警告。
下面的玩具代码(为清楚起见已大大简化了)演示了该问题-它可以编译并运行而不会泄漏内存(如运行时将打印到的分配的对象计数所指示的stdout那样),但是如果我scan-build在其上运行,我得到以下输出:
$ scan-build g++ testrefcount.cpp -o testrefcount
scan-build: Using '/Users/jaf/checker-279/bin/clang' for static analysis
testrefcount.cpp:43:54: warning: Use of memory after it is freed
const MyRefCountedObject * GetObject() const {return _obj;}
^~~~~~~~~~~
testrefcount.cpp:52:8: warning: Potential memory leak
}
^
2 warnings generated.
scan-build: 2 bugs found.
scan-build: Run 'scan-view /var/folders/q9/9w3p5x650wgfpbcws3zhsc6h0000gn/T/scan-build-2019-01-12-122209-5219-1' to examine bug reports.
Run Code Online (Sandbox Code Playgroud)
我的问题是,有什么办法可以修改我的代码,以使Clang的静态分析器不会在这里发出假阳性?我想我可以在中包装引用计数方法#ifndef __clang_analyzer__,但这似乎是一个丑陋的解决方案(类似于将磁带放在“检查引擎”灯上),这将阻止CSA检测到此代码的任何实际问题,因此我想如果有更好的方法,宁愿避免这种情况。(是的,我知道shared_ptr和intrusive_ptr等等-我不知道他们是如何处理这个问题)
独立的示例代码如下:
#include <stdio.h>
// This value will keep track of the …Run Code Online (Sandbox Code Playgroud) c++ ×5
shared-ptr ×2
.net ×1
algorithm ×1
boost ×1
c ×1
c# ×1
concurrency ×1
ctypes ×1
debugging ×1
ios ×1
locking ×1
mutex ×1
objective-c ×1
performance ×1
python ×1
qshareddata ×1
qt ×1
rust ×1
weak-ptr ×1