У меня есть задача показать разницу между синхронизированным и несинхронизированным многопоточным процессом. Поэтому я написал приложение, имитирующее вывод денег с банковских счетов клиентов. Каждое из нескольких потоков выбирает случайного пользователя и снимает деньги со счета. Каждый поток должен удалять каждую учетную запись один раз. В первый раз потоки синхронизируются, но во второй раз они не являются. Таким образом, должна быть разница между учетными записями, снятыми синхронными и несинхронизированными потоками. И разница должна отличаться для разных пользователей и потоков. Но в моем приложении у меня есть разница только для 1000 потоков. Поэтому мне нужно, чтобы результаты несинхронизированных потоков сильно отличались от тех, которые были синхронизированы. Класс пользователя:Многопоточный доступ к списку C#
public class User : IComparable
{
public string Name { get; set; }
public int Start { get; set; }
public int FinishSync { get; set; }
public int FinishUnsync { get; set; }
public int Hypothetic { get; set; }
public int Differrence { get; set; }
...
}
Метод, который забирает деньги:
public void Withdraw(ref List<User> users, int sum, bool isSync)
{
int ind = 0;
Thread.Sleep(_due);
var rnd = new Random(DateTime.Now.Millisecond);
//used is list of users, withrawed by the thread
while (_used.Count < users.Count)
{
while (_used.Contains(ind = rnd.Next(0, users.Count))) ; //choosing a random user
if (isSync) //isSync = if threads syncroized
{
if (Monitor.TryEnter(users[ind]))
{
try
{
users[ind].FinishSync = users[ind].FinishSync - sum;
}
finally
{
Monitor.Exit(users[ind]);
}
}
}
else
{
lock (users[ind])
{
users[ind].FinishUnsync = users[ind].FinishUnsync - sum;
}
}
_used.Add(ind);
}
done = true;
}
И нити созданы таким образом:
private void Withdrawing(bool IsSync)
{
if (IsSync)
{
for (int i = 0; i < _num; i++)
{
_withdrawers.Add(new Withdrawer(Users.Count, _due, _pause));
_threads.Add(new Thread(delegate()
{ _withdrawers[i].Withdraw(ref Users, _sum, true); }));
_threads[i].Name = i.ToString();
_threads[i].Start();
_threads[i].Join();
}
}
else
{
for (int i = 0; i < _num; ++i)
{
_withdrawers.Add(new Withdrawer(Users.Count, _due, _pause));
_threads.Add(new Thread(delegate()
{ _withdrawers[i].Withdraw(ref Users, _sum, false); }));
_threads[i].Name = i.ToString();
_threads[i].Start();
}
}
}
Я изменил ВЫВЕСТИ класс таким образом, bc проблема могла заключаться в создании потоков отдельно от делегата:
class Withdrawer
{
private List<int>[] _used;
private int _due;
private int _pause;
public int done;
private List<Thread> _threads;
public Withdrawer(List<User> users, int n, int due, int pause, int sum)
{
_due = due;
_pause = pause;
done = 0;
_threads = new List<Thread>(users.Count);
InitializeUsed(users, n);
CreateThreads(users, n, sum, false);
_threads.Clear();
while (done < n) ;
Array.Clear(_used,0,n-1);
InitializeUsed(users, n);
CreateThreads(users, n, sum, true);
}
private void InitializeUsed(List<User> users, int n)
{
_used = new List<int>[n];
for (int i = 0; i < n; i++)
{
_used[i] = new List<int>(users.Count);
for (int j = 0; j < users.Count; j++)
{
_used[i].Add(j);
}
}
}
private void CreateThreads(List<User> users, int n, int sum, bool isSync)
{
for (int i = 0; i < n; i++)
{
_threads.Add(new Thread(delegate() { Withdraw(users, sum, isSync); }));
_threads[i].Name = i.ToString();
_threads[i].Start();
}
}
public void Withdraw(List<User> users, int sum, bool isSync)
{
int ind = 0;
var rnd = new Random();
while (_used[int.Parse(Thread.CurrentThread.Name)].Count > 0)
{
int x = rnd.Next(_used[int.Parse(Thread.CurrentThread.Name)].Count);
ind = _used[int.Parse(Thread.CurrentThread.Name)][x];
if (isSync)
{
lock (users[ind])
{
Thread.Sleep(_due);
users[ind].FinishSync -= sum;
}
}
else
{
Thread.Sleep(_due);
users[ind].FinishUnsync -= sum;
}
_used[int.Parse(Thread.CurrentThread.Name)][x] = _used[int.Parse(Thread.CurrentThread.Name)][_used[int.Parse(Thread.CurrentThread.Name)].Count - 1];
_used[int.Parse(Thread.CurrentThread.Name)].RemoveAt(_used[int.Parse(Thread.CurrentThread.Name)].Count - 1);
Thread.Sleep(_pause);
}
done++;
}
}
Теперь проблема в значении FinishUnSync верна, а значения FinishSync абсолютно отсутствуют. Thread.Sleep (_due); и Thread.Sleep (_pause);
используются для «удержания» ресурса, bc моя задача - поток должен получить ресурс, удерживать его за _due ms, а после обработки ждать _pause ms до завершения.
Если вы пишете код, чтобы показать разницу, это синхронный и асинхронный код, но вы должны искусственно раздуть разницу между этими двумя методами, тогда ваш пример неверен. – Gusdor
Я бы предположил, что несинхронизированный доступ к контейнерам, не связанным с потоками, дает непредсказуемые результаты, которые иногда включают в себя правильные результаты. – gap
Какая версия рамки? .NET 4.5 предоставляет новую поточную сборку для одновременного доступа. – Fals