15 hours ago

Can birkaç sene evvel core.sync.mutex'i kullanarak bir array pool implement etmişti. Biraz sadeleştirerek şu örnek ile denemiştim:

https://forum.dlang.org/post/ghuzblcnqosxiwbkmjgp@forum.dlang.org

Olasılıkların olduğu, yazı/tura hatta paranın dik gelmesi falan eğlenceliydi hani! Ancak orada da bahsettiğim gibi bir hata alıyorduk ve bunu Can da kabul ediyordu. Yani özetle bir şeyleri yanlış yapıyorduk...

On Friday, 16 December 2022 at 17:42:03 UTC, Can Alpay Çiftci wrote:

>

On Thursday, 15 December 2022 at 23:21:13 UTC, Ali Çehreli wrote:

>

Evet, hiçbir değişiklik yapmadan patlıyor. Ben Linux üzerindeyim. Birazdan anlamaya çalışırım. Buldum:

finally
{
    if (lockTaken)
    {
        mutex.tryLock_nothrow();
    }
}

unlock_nothrow olacakmış.

Fakat tryLock_nothrow'un döndürdüğü değeri doğru kullandığından emin misin? (Belgesi pek açıklayıcı değil.) 'false' döndürdüğünde işine devam etme hakkın oluyor mu? Çünkü kilitle(ye)mediğinde 'false' döndürüyormuş.

Yanlış kullanıyorum. Belge açıklayacı olmasa da bu konuda belge değil işlev adından bile çıkacak bir nenmiş aslında. Benim hatam. Kiliti alamadığında alana kadar spin atan(threadi boşta bekleten) bir method varsa onu kullanmak isterdim. Bu method o konuda ne kadar istekli bilmiyorum. Bekliyor mu zaman aşımı hatası atıyor mu?

Burada nothrow methodların olup error throw etmesi garip. Keşke onun yerine throw olsa olanları methodda bildirsek.(Javada şimdi kontrol ettim Exception yakalanmaz ise throws diye belirtmek gerekiyor. Error isteğe bağlı.)

Az önce böyle bir dizi birikintisine ihtiyaç duyunca hataları giderdim. Belki deneyip kullanmak isteyen olur diye paylaşıyorum:

module arraypool;

import core.sync.mutex;

auto selectBucketIndex(size_t bufferSize) {
  import std.math.exponential;
  const calc = bufferSize - 1 | 15;
  return cast(size_t) log2(cast(double)calc) - 3;
}

auto getMaxSizeForBucket(size_t binIndex)
  => 16UL << binIndex;

class ArrayPool(T) {
  enum len = 1024 * 1024; // default Max Array Length
  enum num = 50; // default Max Number Of Arrays Per Bucket

  Bucket!T[] buckets;

  this(size_t maxArrayLength = len,
       size_t maxArraysPerBucket = num) {
      enum minimumArrayLength = 0x10;
      enum maximumArrayLength = 0x40000000;

      if (maxArrayLength > maximumArrayLength) {
          maxArrayLength = maximumArrayLength;
      } else if (maxArrayLength < minimumArrayLength) {
          maxArrayLength = minimumArrayLength;
      }

      size_t poolId = id;
      size_t maxBuckets = maxArrayLength.selectBucketIndex();
      buckets = new Bucket!T[maxBuckets + 1];
      for (size_t i = 0; i < buckets.length; i++) {
          buckets[i] = new Bucket!T(i.getMaxSizeForBucket(), maxArraysPerBucket, poolId);
      }
  }

  auto id() => toHash();

  T[] rent(size_t minimumLength) {
      if (minimumLength == 0) return new T[0];

      T[] buffer;
      size_t index = minimumLength.selectBucketIndex();
      if (index < buckets.length) {
          enum maxBucketsToTry = 2;
          size_t i = index;

          do {
              buffer = buckets[i].rent();
              if (buffer !is null) {
                  return buffer;
              }
          } while (++i < buckets.length && i != index + maxBucketsToTry);

          buffer = new T[buckets[index].length];
      } else {
          buffer = new T[minimumLength];
      }
      return buffer;
  }

  void returnToPool(T[] array, bool clearArray = false) {
    if (array.length == 0) return;
    size_t bucketIndex = array.length.selectBucketIndex();
    bool haveBucket = bucketIndex < buckets.length;

    if (haveBucket) {
      if (clearArray) array[] = T.init;
      buckets[bucketIndex].free(array);
    }
  }
}

class Bucket(T) {
  private {
    immutable size_t length, poolId;
    size_t index;
    T[][] bucket;
  }
  Mutex mutexM;

  this(size_t bufferLength, size_t numberOfBuffer, size_t poolId) {
    this.mutexM = new Mutex();
    this.bucket = new T[][numberOfBuffer];
    this.length = bufferLength;
    this.poolId = poolId;
  }

  auto id() => toHash();

  T[] rent() {
    T[] buffer;
    bool lockTaken;

    try {
      mutexM.lock();
      lockTaken = true;

      if (index < bucket.length) {
        buffer = bucket[index];
        bucket[index++] = null;
        if (buffer is null) buffer = new T[length];
      }

    } finally {

      if (lockTaken) mutexM.unlock();
    }
    return buffer;
  }

  void free(T[] array) {
    if (array.length != length) {
      throw new Exception("Buffer not from pool");
    }
    bool lockTaken;

    try {
      mutexM.lock();
      lockTaken = true;

      if (index > 0) bucket[--index] = array;

    } finally {

      if (lockTaken) mutexM.unlock();
    }
  }
}

SDB@79

15 hours ago

On Tuesday, 22 October 2024 at 05:55:19 UTC, Salih Dincer wrote:

>

Belki deneyip kullanmak isteyen olur diye paylaşıyorum:

Denemek için bir unittest de yazdım. Bu unlock'lu versiyon içindi. Ekrana paranın geleceği olasılıkları görmek için unittest'i void main()'e çevirip version = print satırını açarsınız.

//version = print;

unittest {
  enum {
    defaultSize = 16,
    repeat = 10,
    bufferSize = 8,
    result = defaultSize * repeat
  }

  Test.counter = 0;
  foreach (_; 0 .. repeat) {
    make16!Test(bufferSize);
  }
  assert(Test.counter == result);
}

struct Test {
  enum Para {
    Yazı, Tura, Dik
  }
  Para c;
  size_t n;

  this(size_t i) {
    c = imported!"std.random".uniform!Para;
    n = i;
  }

  static size_t counter;
  ~this() { ++counter; }
}

auto make16(T)(size_t capacity) in (capacity <= 16) {
  auto aps = new ArrayPool!T;
  auto mem = aps.rent(capacity);
  foreach (i, ref item; mem) {
    item = T(i + 1);
  }
  version (print) {
    import std.stdio;
    write('[');
    foreach(ref item; mem[0..$-1])
      item.c.write(", ");
    mem[$-1].c.writeln(']');
  }
  aps.returnToPool(mem);
}

SDB@79