Работает ли lock внутри потоков, запущенных в semaphoreslim?
часть кода в методе запускаемом в Thread ограждена lock(locker){для 1 потока} без семафора потоки работают корректно. в семафоре такое ощущение, что локер не работает Если в семафоре не работает локер, то как ограничить часть кода только для 1го, если семафор запускать (5,5) например?
код запуска потоков
_pool = new SemaphoreSlim(5, 5);
await Task.Run(() =>
{
for (int i = 0; i < 2000; i++)
{
Thread t = new Thread(new ParameterizedThreadStart(CircleForPool));
t.Start(null);
}
});
код метода:
public void CircleForPool(object obj)
{
_pool.Wait();
//некоторый код
lock(Locker)
{
//некоторый код
}
//некоторый код
_pool.Release();
}
так же замечено странное поведение в семафоре, кода, который не лочится дополнительно:
string[] lines = File.ReadAllLines("keys.txt");
KeyApi = lines[new Random().Next(lines.Length)];
тут берётся случайное значение из файла, в котором около 200 строк, и на старте сразу 6 потоков из 10 (ограниченных семафором) берут один и тот же ключ
так же подобный код в локе (этот метод вызывается внутри потока):
public string TakeFolder(string domen)
{
string folder = "";
lock (locker)
{
string[] profile = File.ReadAllLines("listprofile.txt");
List<string> newprofile = new List<string>();
int count = profile.Where(x => x.Contains(domen)).Count();
int rndtake = new Random().Next(1, count + 1);
int num = 0;
for (int i = 0; i < profile.Length; i++)
{
if (profile[i].Contains(domen))
{
num += 1;
}
if (profile[i].Contains(domen) && folder == "")
{
folder = profile[i].Split(':')[1];
}
else
{
newprofile.Add(profile[i]);
}
}
if (folder != "")
{
File.WriteAllLines("listprofile.txt", newprofile.ToArray());
Thread.Sleep(3000);
}
}
return folder;
}
Ответы (1 шт):
new Random() использует текущее время в качестве начального seed. Поэтому когда вы вызываете new Random() одновременно вне лока - вы получаете один и тот же ключ. Используйте общий объект Random - положите его в поле или в статику, и оберните вызов Next в лок (с отдельным locker).
https://docs.microsoft.com/en-us/dotnet/api/system.random.-ctor?view=net-5.0#System_Random__ctor
In .NET Framework, the default seed value is derived from the system clock, which has finite resolution. As a result, different Random objects that are created in close succession by a call to the parameterless constructor have identical default seed values and, therefore, produce identical sets of random numbers. You can avoid this problem by using a single Random object to generate all random numbers.
В .NET Core будет работать без выноса в поле класса, там это починили на уровне фреймворка.