d的跟踪.

这里
:需要手动初化.__gshared是正确的方法吗?
这是线程本地存储用途.正如D运行时对dmd-profile命令行开关那样,可拥有模块级Appender,它为该线程收集数据而无需担心竞争条件.
:解锁互斥锁?
仅当每个线程退出并组合结果时,才需要互斥锁.每个static ~this()都可获取互斥锁并添加其结果到全局Appender.而该"全局"Appendershared或__gshared不重要.
:__gshared并不在分析器上放共享类型属性.正确.
高效无锁appender会很酷.

import std;
import std.datetime.stopwatch;
import core.thread;
import core.atomic;
import core.internal.spinlock;

enum workerCount = 8;
enum threadRunTime = 4.seconds;
enum mainRunTime = threadRunTime + 1.seconds;

shared struct ScopeLock {
  @disable this(this);
  @disable void opAssign(ref const(typeof(this)));

  SpinLock * lock;

  this(shared(SpinLock) * lock) {
    this.lock = lock;
    lock.lock();
  }

  ~this() {
    lock.unlock();
  }
}

struct Collector {
  long[] data;

  shared(SpinLock) lock;

  auto scopeLock() shared {
    return ScopeLock(&lock);
  }

  // 加`收集器`的数据指针
  void add(long i) shared {
    auto sl = scopeLock();

    /// 加针方法,读代码
    data ~= i;
  }

  // 添加`此收集器的数据`到`指定数组`中,
  void aggregate(ref long[] where) shared {
    auto sl = scopeLock();

    where ~= data.sum;
    data.length = 0;
    (cast(long[])data).assumeSafeAppend();
  }
}

// 帮助我们信任代码的变量,主结束时打印
long allThatHasBeenDumped = 0;
// 仅用于验证代码
shared long allCollectedByThreads;

synchronized class Dumper {
private:
  shared(Collector)*[] collectors;

  void register(shared(Collector) * collector) shared {
    writeln("注册 ", collector);
    collectors ~= collector;
  }

  // 转储当前结果
  void dump(File output) shared {
    long[] data;

    foreach (collector; collectors) {
      collector.aggregate(data);
    }

    const allData = data.sum;

    if (allData != 0) {
      stdout.writefln!"收集了:%-(\n  %,s%)"(data);
      allThatHasBeenDumped += allData;
    }
  }
}

shared(Dumper) dumper;

shared static this() {
  writeln("造转储器");
  dumper = new Dumper();
}

shared(Collector) * collector;

static this() {
  writeln("造收集器");
  collector = new shared(Collector)();
  dumper.register(cast(shared)collector);
}

// 主线程
void doWork() {
  try {
    doWorkImpl();

  } catch (Throwable exc) {
    stderr.writeln("抓可抛:", exc.msg);
  }
}

// 每个线程的实现
void doWorkImpl() {
  auto sw = StopWatch();
  sw.start();

  long i = 0;
  while (sw.peek < threadRunTime) {
    (cast(shared)collector).add(i);
    ++i;
  }

  --i;
  auto total = i * (i + 1) / 2;
  writefln("收集了%s,%s,%s",i,total,collector);

  atomicOp!"+="(allCollectedByThreads, total);
}

void main() {
  writeln("主开始");
  iota(workerCount).each!(_ => spawn(&doWork));

  auto sw = StopWatch();
  sw.start();

  while (sw.peek < mainRunTime) {
    dumper.dump(stdout);
    Thread.sleep(100.msecs);
  }

  //最终收集(并转储)
  dumper.dump(stdout);

  assert(allThatHasBeenDumped == allCollectedByThreads);
}
posted @   zjh6  阅读(17)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示