Потокозащищённый LinkedList - C#
Формулировка задачи:
Есть консольное приложение, работающее со списком LinkedList, реализованы функции добавления/удаления/изменения узлов. По заданию оно должно быть потокозащищённым и, следовательно, должна быть какая-то демонстрация - несколько потоков должны попытаться изменить список одновременно, но в итоге выполнить всё культурно по очереди. Затруднения возникают, с тем чтобы в несколько потоков выполнить команды типа , например. Судя по мануалам, нужно создавать новый класс, уже он должен обращаться к методам из класса LinkedList, но так не выйдет, поскольку userList создаётся в Main(). Несколько идей было, вроде из Main передавать параметры в методы, там уже создавать список, вызывать все эти методы и прочее, но слишком сложно выходит, мне кажется. Надеюсь на любые советы по теме, код полностью приложу ниже (писал на основе коротенького примера со StackOverflow, половина кода - консольное меню):
userList.AddFirst(data)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace theLastSharpian
{
public class Node
{
public Node next;
public Object data;
}
public class LinkedList
{
private Node head;
public void printAllNodes()
{
Console.WriteLine("List of nodes:");
if (head == null)
Console.WriteLine("| List empty.");
else
{
Console.WriteLine("| № next data");
Console.WriteLine("|--------------------------");
Node current = head;
int i = 1;
while (current != null)
{
string tempword = "link";
if (current.next == null)
tempword = "null";
Console.WriteLine("| {0}. {1} {2};", i++, tempword, current.data);
current = current.next;
}
}
}
public void AddFirst(Object data)
{
if (head == null)
{
head = new Node();
head.data = data;
head.next = null;
}
else
{
Node tmp = new Node();
Node toAdd = new Node();
toAdd.data = data;
toAdd.next = head;
head = toAdd;
tmp = head.next;
}
}
public void AddLast(Object data)
{
if (head == null)
{
head = new Node();
head.data = data;
head.next = null;
}
else
{
Node toAdd = new Node();
toAdd.data = data;
Node current = head;
while (current.next != null)
current = current.next;
current.next = toAdd;
}
}
public void AddAfter(int x, Object data)
{
if (head == null)
Console.WriteLine("List empty");
else
{
Node toAdd = new Node();
toAdd.data = data;
Node temp = head;
Node current = head;
for (int i = 0; i < x; i++)
{
temp = current;
current = current.next;
}
temp.next = toAdd;
toAdd.next = current;
}
}
public void ChangeData(int x, Object data)
{
if (head == null)
Console.WriteLine("List empty");
else
{
Node current = head;
for (int i = 0; i < x-1; i++)
current = current.next;
current.data = data;
}
}
public void DeleteFirst()
{
if (head == null)
Console.WriteLine("List already empty");
else
{
Node current = head;
head = current.next;
current.next = null;
current.data = null;
Console.WriteLine("Item deleted");
if (head == null)
Console.WriteLine("List now empty");
}
}
public void DeleteLast()
{
if (head == null)
Console.WriteLine("List already empty");
else
{
Node temp = head;
Node current = head;
while (current.next != null)
{
temp = current;
current = current.next;
}
current.next = null;
current.data = null;
temp.next = null;
Console.WriteLine("Item deleted");
if (temp.data == null)
{
head = null;
Console.WriteLine("List now empty");
}
}
}
public void DeleteAfter(int x)
{
if (head == null)
Console.WriteLine("List empty");
else
{
Node temp = head;
Node current = head;
for (int i = 0; i < x; i++)
{
temp = current;
current = current.next;
}
if (current == null)
Console.WriteLine("Error. There is nothing after last node. Maybe DeleteLast fits your needs?");
else
{
temp.next = current.next;
current.next = null;
current.data = null;
Console.WriteLine("Item deleted");
if (temp.data == null)
{
head = null;
Console.WriteLine("List now empty");
}
}
}
}
}
/// <summary>
/// можно сделать вывод покрасивее, менее захламленным
/// если ввести некорректное N получится нехорошо. можно вообще добавить отдельный метод просто для ввода корректного N
/// </summary>
class Program
{
static void Main()
{
Console.Title = "Super non-cool app for ITS specialists - linked list with such thread safety wow";
string key = "800";
int N, kol=0, kol2;
LinkedList userList = new LinkedList();
do
{
Console.WriteLine("------------------------------------------------------------\n Any key to proceed to menu");
Console.ReadKey();
Console.Clear();
Console.WriteLine("0. Exit program\n-userList [{0} items] manual control:\nf. Fill userList\n1. Print all nodes\n2. Change data in node", kol);
Console.WriteLine("3. Add node(s) with AddLast\n4. Add node(s) with AddFirst\n5. Add node with AddAfter");
Console.WriteLine("6. Delete node(s) with DeleteLast\n7. Delete node(s) with DeleteFirst\n8. Delete node with DeleteAfter\n9. Delete all nodes");
Console.WriteLine("-non-userList commands:\nt. non-usable thread info");
key = Console.ReadLine();
string data;
switch (key)
{
case "1":
Console.WriteLine("------------------------------------------------------------");
userList.printAllNodes();
break;
case "2":
Console.WriteLine("------------------------------------------------------------");
Console.WriteLine("Select node for ChangeData:");
userList.printAllNodes();
if (kol > 0)
{
N = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter data: ");
data = Console.ReadLine();
userList.ChangeData(N, data);
}
else
Console.WriteLine("Can not process empty list");
break;
case "3":
Console.WriteLine("------------------------------------------------------------");
Console.Write("AddLast. How much nodes? ");
N = Convert.ToInt32(Console.ReadLine());
kol2 = kol + N;
while (kol != kol2)
{
Console.Write("{0} = ", kol + 1);
data = Console.ReadLine();
userList.AddLast(data);
kol++;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "4":
Console.WriteLine("------------------------------------------------------------");
Console.Write("AddFirst. How much nodes? ");
N = Convert.ToInt32(Console.ReadLine());
kol2 = kol + N;
int i = N;
while (kol != kol2)
{
Console.Write("{0} = ", i);
data = Console.ReadLine();
userList.AddFirst(data);
kol++;
i--;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "5":
Console.WriteLine("------------------------------------------------------------");
Console.WriteLine("Select node for AddAfter:");
userList.printAllNodes();
N = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter data: ");
data = Console.ReadLine();
kol2 = kol + 1;
while (kol != kol2)
{
userList.AddAfter(N, data);
kol++;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "6":
Console.WriteLine("------------------------------------------------------------");
Console.Write("DeleteLast. How much nodes? ");
N = Convert.ToInt32(Console.ReadLine());
kol2 = kol - N;
while (kol != kol2)
{
userList.DeleteLast();
kol--;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "7":
Console.WriteLine("------------------------------------------------------------");
Console.Write("DeleteFirst. How much nodes? ");
N = Convert.ToInt32(Console.ReadLine());
kol2 = kol - N;
while (kol != kol2)
{
userList.DeleteFirst();
kol--;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "8":
Console.WriteLine("------------------------------------------------------------\n");
Console.WriteLine("Select node for DeleteAfter:");
userList.printAllNodes();
N = Convert.ToInt32(Console.ReadLine());
kol2 = kol - 1;
while (kol != kol2)
{
userList.DeleteAfter(N);
kol--;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "9":
Console.WriteLine("------------------------------------------------------------");
Console.WriteLine("Deleting all nodes");
while (kol != 0)
{
userList.DeleteLast();
kol--;
}
Console.WriteLine("Now there is {0} items", kol);
break;
case "f":
userList.AddLast("first");
userList.AddLast("second");
userList.AddLast("third");
userList.AddLast("fourth");
userList.AddLast("fifth");
userList.AddLast("sixth");
userList.AddLast("last");
Console.WriteLine("7 items added");
kol = kol + 7;
Console.WriteLine("Now there is {0} items", kol);
break;
case "t":
Thread mainThread = Thread.CurrentThread;
mainThread.Name = "Main Thread";
Console.WriteLine("Имя домена приложения: {0}\nID контекста: {1}\nИмя потока: {2}\nЗапущен ли поток? {3}\nПриоритет потока: {4}\nСостояние потока: {5}",
Thread.GetDomain().FriendlyName, Thread.CurrentContext.ContextID, mainThread.Name, mainThread.IsAlive, mainThread.Priority, mainThread.ThreadState);
break;
case "0":
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine("No correct key");
break;
}
} while (key != "0");
Console.ReadLine();
}
}
}Решение задачи: «Потокозащищённый LinkedList»
textual
Листинг программы
lock (_locker) for (int i = 0; i < 5; i++)