/// <summary> /// Construct with the specified minimum concurrency level. /// </summary> /// <remarks> /// minConcurrencyLevel must be at least one, an exception is thrown if it is less than 1 (i.e. zero or negative). /// The actual concurrency level is required to be a power of two, thus the actual level is chosen to be the /// nearest power of two that is greater than or equal to minConcurrencyLevel/ /// </remarks> public DefaultRandomSeedSource(int minConcurrencyLevel) { if (minConcurrencyLevel < 1) { throw new ArgumentException("Must be at least 1.", nameof(minConcurrencyLevel)); } // The actual concurrency level is required to be a power of two, thus the actual level is chosen // to be the nearest power of two that is greater than or equal to minConcurrencyLevel. int concurrencyLevel = MathUtils.CeilingToPowerOfTwo(minConcurrencyLevel); _concurrencyLevel = (uint)concurrencyLevel; // Create high quality random bytes to init the seed PRNGs. byte[] buf = GetCryptoRandomBytes(concurrencyLevel * 8); // Init the seed PRNGs and associated sync lock objects. // Note. In principle we could just use each RNG object as the sync lock for itself, but that is considered bad practice. _seedRngArr = new Xoshiro256StarStarRandom[concurrencyLevel]; _lockArr = new object[concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { // Init rng. ulong seed = BitConverter.ToUInt64(buf, i * 8); _seedRngArr[i] = new Xoshiro256StarStarRandom(seed); _lockArr[i] = new object(); } }
/// <summary> /// Construct with the specified minimum concurrency level. /// </summary> /// <remarks> /// minConcurrencyLevel must be at least one, an exception is thrown if it is less than 1 (i.e. zero or negative). /// The actual concurrency level is required to be a power of two, thus the actual level is chosen to be the /// nearest power of two that is greater than or equal to minConcurrencyLevel/ /// </remarks> public DefaultRandomSeedSource(int minConcurrencyLevel) { if (minConcurrencyLevel < 1) { throw new ArgumentException("Must be at least 1.", nameof(minConcurrencyLevel)); } // The actual concurrency level is required to be a power of two, thus the actual level is chosen // to be the nearest power of two that is greater than or equal to minConcurrencyLevel. int concurrencyLevel = MathUtils.CeilingToPowerOfTwo(minConcurrencyLevel); _concurrencyLevel = (uint)concurrencyLevel; // Create high quality random bytes to init the seed PRNGs. byte[] buf = GetCryptoRandomBytes(concurrencyLevel * 8); // Init the seed PRNGs and associated sync lock objects. _seedRngArr = new Xoshiro256StarStarRandom[concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { // Init rng. ulong seed = BitConverter.ToUInt64(buf, i * 8); _seedRngArr[i] = new Xoshiro256StarStarRandom(seed); } // Create a semaphore that will allow N threads into a critical section, and no more. _semaphore = new SemaphoreSlim(minConcurrencyLevel, concurrencyLevel); }
/// <summary> /// Construct with the specified minimum concurrency level. /// </summary> /// <param name="minConcurrencyLevel">Minimum concurrency level.</param> /// <remarks> /// minConcurrencyLevel must be at least one, an exception is thrown if it is less than 1 (i.e. zero or negative). /// The actual concurrency level is required to be a power of two, thus the actual level is chosen to be the /// nearest power of two that is greater than or equal to minConcurrencyLevel. /// </remarks> public DefaultRandomSeedSource(int minConcurrencyLevel) { if (minConcurrencyLevel < 1) { throw new ArgumentException("Must be at least 1.", nameof(minConcurrencyLevel)); } // The actual concurrency level is required to be a power of two, thus the actual level is chosen // to be the nearest power of two that is greater than or equal to minConcurrencyLevel. int concurrencyLevel = MathUtils.CeilingToPowerOfTwo(minConcurrencyLevel); _concurrencyLevel = (uint)concurrencyLevel; // Create high quality random bytes to init the seed PRNGs. Span <byte> buf = stackalloc byte[concurrencyLevel << 3]; // Note. Generating crypto random bytes can be very slow, relative to a PRNG; we may even have to wait // for the OS to have sufficient entropy for generating the bytes. using (RNGCryptoServiceProvider cryptoRng = new RNGCryptoServiceProvider()) { cryptoRng.GetBytes(buf); } // Init the seed PRNGs and associated sync lock objects. // Note. In principle we could just use each RNG object as the sync lock for itself, but that is considered bad practice. _seedRngArr = new Xoshiro256StarStarRandom[concurrencyLevel]; _lockArr = new object[concurrencyLevel]; for (int i = 0; i < concurrencyLevel; i++) { // Init rng. ulong seed = BitConverter.ToUInt64(buf.Slice(i << 3, 8)); _seedRngArr[i] = new Xoshiro256StarStarRandom(seed); _lockArr[i] = new object(); } }