标签: copy-on-write

关于Copy-On-Write和shared_ptr的困惑

我在网上搜索并阅读了Boost文档shared_ptr.在SO上有一个响应,表示shared_ptr对于写入时复制(COW)糟透了,TR!并且已将其从字符串库中删除.关于SO的大多数建议都说使用shared_ptr而不是常规指针.

该文档还讨论了使用std::unique()COW指针,但我没有找到任何示例.

是否有关于为您执行COW的智能指针或让您的对象使用新shared_ptr的克隆对象然后修改克隆对象的讨论?

示例:食谱和配料

struct Nutrients;

struct Ingredient
{
    Ingredient(const std::string& new_title = std::string(""))
        : m_title(new_title)
        { ; }
    std::string m_title;
    Nutrients   ing_nutrients;
};

struct Milk : public Ingredient
    : Ingredient("milk")
{ ; }

struct Cream : public Ingredient
    : Ingredient("cream")
{ ; }

struct Recipe
{
    std::vector< boost::shared_ptr<Ingredient> > m_ingredients;
    void append_ingredient(boost::shared_ptr<Ingredient> new_ingredient)
    {
        m_ingredients.push_back(new_ingredient);
        return;
    }
    void replace_ingredient(const std::string& original_ingredient_title,
                            boost::shared_ptr<Ingredient> new_ingredient)
    {
        // Confusion here …
Run Code Online (Sandbox Code Playgroud)

c++ boost copy-on-write shared-ptr

8
推荐指数
1
解决办法
3421
查看次数

为什么子进程和父进程的变量地址相同

这是我的代码

int main()
{
  pid_t pid;
  int y = 3;  
  if ( (pid = fork()) <0 )
   return -1;;

  if( pid == 0 )  /* child */
  {
    printf(" before: %d %p\n", y, &y );
    y *= 10;
    printf("after: %d %p\n", y, &y );
  }
  else /* father */
  {
   sleep(1);
   printf("father: %d %p\n" , y , &y );

  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

该程序的输出如下:

before: 3 ffbff440
after: 30 ffbff440
father: 3 ffbff440
Run Code Online (Sandbox Code Playgroud)

我的问题是为什么孩子和父母的变量的地址相同但价值不同?

c unix fork copy-on-write

8
推荐指数
1
解决办法
3956
查看次数

获取fork()的copy-on-write行为,不带fork()

我有一个大缓冲区:

char *buf = malloc(1000000000); // 1GB
Run Code Online (Sandbox Code Playgroud)

如果我分叉一个新进程,它将有一个buf,它与父进程的buf共享内存,直到一个或另一个写入它.即使这样,内核也只需要分配一个新的4KiB块,其余的将继续共享.

我想复制一下buf,但我只想改变一点副本.我想要不写分支的写时复制行为.(就像你在分叉时免费获得的那样.)

这可能吗?

c fork copy-on-write

8
推荐指数
1
解决办法
2010
查看次数

在Java中,我可以依赖于原子的引用赋值来实现写入时的复制吗?

如果我在多线程环境中有一个不同步的java集合,并且我不想强制集合的读者同步[1],那么我是一个同步编写器并使用引用赋值的原子性可行的解决方案吗?就像是:

private Collection global = new HashSet(); // start threading after this

void allUpdatesGoThroughHere(Object exampleOperand) {
  // My hypothesis is that this prevents operations in the block being re-ordered
  synchronized(global) {
    Collection copy = new HashSet(global);
    copy.remove(exampleOperand);
    // Given my hypothesis, we should have a fully constructed object here. So a 
    // reader will either get the old or the new Collection, but never an 
    // inconsistent one.
    global = copy;    
  }
}

// Do multithreaded reads here. …
Run Code Online (Sandbox Code Playgroud)

java multithreading synchronization locking copy-on-write

8
推荐指数
2
解决办法
3413
查看次数

使用shared_ptr复制写入

所以我有一个简单的cow_ptr.它看起来像这样:

template<class T, class Base=std::shared_ptr<T const>>
struct cow_ptr:private Base{
  using Base::operator*;
  using Base::operator->;
  using Base::operator bool;
  // etc

  cow_ptr(std::shared_ptr<T> ptr):Base(ptr){}

  // defaulted special member functions

  template<class F>
  decltype(auto) write(F&& f){
    if (!unique()) self_clone();
    Assert(unique());
    return std::forward<F>(f)(const_cast<T&>(**this));
  }
private:
  void self_clone(){
    if (!*this) return;
    *this = std::make_shared<T>(**this);
    Assert(unique());
  }
};
Run Code Online (Sandbox Code Playgroud)

这可以保证它拥有一个非常量T并确保它在unique何时出现.write([&](T&){}).

的折旧.unique()似乎表明这种设计是有缺陷的.

我猜测如果我们从线程A中的cow_ptr<int> ptrwith 开始1,将它传递给线程B,使其唯一,修改它2,传ptr回它并在线程中读取它A我们已经生成了竞争条件.

我该如何解决?我可以简单地添加内存屏障write吗?哪一个?或者问题更根本? …

c++ copy-on-write memory-barriers c++17

8
推荐指数
1
解决办法
334
查看次数

具有写时复制功能的纯功能数据结构?

我想拥有功能数据结构的优势(可以共享结构的多个数据版本),但能够以命令式方式修改它.

我正在考虑的(以及可能的用途):一个RPG游戏,其中存储了整个游戏历史(例如,允许回到过去).使用copy-on-write,我可以简单地克隆保持游戏状态的结构并通过引入新的转弯来修改它 - 但是可以访问较早的转弯(不一定是所有这些转弯,可能只是游戏状态的选定快照),而不是每次必须复制一切的惩罚.


让我们说foo是一张地图.

bar = foo.clone()
Run Code Online (Sandbox Code Playgroud)

没有任何foo结构(例如,树)被复制.但是,从现在开始,bar它被视为副本,并且不允许任何更改传播回`foo'.

baz = bar[someKey]
baz.modifyInSomeWay()
Run Code Online (Sandbox Code Playgroud)

现在

  • 创建一个新对象,这是一个修改过的副本baz.
  • bar用新地图替换,保留新的baz(可能保留一些foo结构).
  • foo 不受影响.

但如果我们那么做......

baz.modifyAgain()
Run Code Online (Sandbox Code Playgroud)

... baz可以修改,因为我们有最新版本的.bar 不需要改变.

所有这些都需要持有的一些版本信息foobar关于增加它foo.clone(),并把它传递给baz某种方式(通过使代理对象?).

此外,已克隆的结构的任何部分都成为"历史的一部分",不能再被更改,这可以在运行时强制执行.


这有点类似于JavaScript的原型,但我更多的是因为它允许更改向上传播.我认为它会像版本控制系统.

  • 这已经完成了,到了什么程度?
  • 这是一个好主意吗?如果没有,有没有办法保存它?
  • 怎么可以实施?我正在考虑在Python之类的高级GC语言之上构建它.

python functional-programming immutability copy-on-write

7
推荐指数
1
解决办法
1619
查看次数

迭代器和引用计数字符串

如果我们考虑使用引用计数的std :: string实现,请考虑以下情况:

int main()
{
  string english = "Hello";
  string german  = english; //refcnt = 2
  string german2 = german;

  /* L1 */ german[1] = 'a';
  /* L2 */ *(german2.begin() + 1) = 'A';

  cout << english << endl << german << endl << german2 << endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

L1和L2会发生什么?引用计数是否已损坏并执行了深层复制?我是这么认为的,但我担心的是,如果发生这种情况,做一个简单的事情:

cout << german[1] << endl; 
Run Code Online (Sandbox Code Playgroud)

还是简单的:

cout << *(german.begin()) << endl;
Run Code Online (Sandbox Code Playgroud)

在非const上下文中将执行不必要的深层复制.我对吗?这些实现如何处理这个细节?

c++ stl copy-on-write

7
推荐指数
1
解决办法
228
查看次数

copy-on-write如何在fork()中工作?

我想知道如何在fork()中发生copy-on-write.

假设我们有一个具有动态int数组的进程A:

int *array = malloc(1000000*sizeof(int));
Run Code Online (Sandbox Code Playgroud)

数组中的元素初始化为一些有意义的值.然后,我们使用fork()创建一个子进程,即B.B将迭代数组并进行一些计算:

for(a in array){
    a = a+1;
}
Run Code Online (Sandbox Code Playgroud)
  1. 我知道B不会立即复制整个数组,但是什么时候子B为数组分配内存?在fork()期间?
  2. 它是一次性分配整个数组,还是只分配一个整数a = a+1
  3. a = a+1;这是怎么发生的?B是否从A读取数据并将新数据写入其自己的数组?

我写了一些代码来探索COW如何工作.我的环境:ubuntu 14.04,gcc4.8.2

#include <stdlib.h>
#include <stdio.h>
#include <sys/sysinfo.h>

void printMemStat(){
    struct sysinfo si;
    sysinfo(&si);
    printf("===\n");
    printf("Total: %llu\n", si.totalram);
    printf("Free: %llu\n", si.freeram);
}

int main(){
    long len = 200000000;
    long *array = malloc(len*sizeof(long));
    long i = 0;
    for(; i<len; i++){
        array[i] = i;
    }

    printMemStat();
    if(fork()==0){
        /*child*/
        printMemStat();

        i = 0;
        for(; i<len/2; i++){
            array[i] = i+1; …
Run Code Online (Sandbox Code Playgroud)

c unix linux fork copy-on-write

7
推荐指数
2
解决办法
6341
查看次数


QList 上的 C++11 基于范围的循环中的“容器分离”是什么?这只是性能问题吗?

这个问题包含一些解决该问题的建议,我想更深入地了解问题到底是:

 QList<QString> q;
 for (QString &x: q) { .. }
Run Code Online (Sandbox Code Playgroud)
  1. 除非容器被声明const,否则 Qt 是否会创建列表的副本,然后迭代该副本?这不是最好的,但如果列表很小(比如 10-20 个 QString),这是可以忍受的。
  2. 这仅仅是性能问题还是可能是一些更深层次的问题?假设我们在循环运行时不添加/删除元素。
  3. 循环中值的修改(假设它是一个引用)仍然有效还是从根本上被破坏了?

c++ foreach qt copy-on-write

7
推荐指数
1
解决办法
671
查看次数