Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am totally new to multithreading. I am try to work on a simple test
I have a list of number from 1 to 100. The function I want to multithread is simply a function to multi the number by 5 then console.writeline the result
class Program
{
public static List data = new List();
public static void Main(string[] args)
{
new Program().run();
foreach(int d in data)
{
Console.WriteLine(d);
}
}
int multiply (int a){
return 5 * a;
}
void run()
{
int threadCount = 5;
Task[] workers = new Task[threadCount];
Task.Factory.StartNew(consumer);
for (int i = 0; i < threadCount; ++i)
{
int workerId = i;
Task task = new Task(() => worker(workerId));
workers[i] = task;
task.Start();
}
for (int i = 0; i < 100; ++i)
{
Console.WriteLine("Queueing work item {0}", i);
inputQueue.Add(i);
Thread.Sleep(50);
}
Console.WriteLine("Stopping adding.");
inputQueue.CompleteAdding();
Task.WaitAll(workers);
outputQueue.CompleteAdding();
Console.WriteLine("Done.");
Console.ReadLine();
}
void worker(int workerId)
{
Console.WriteLine("Worker {0} is starting.", workerId);
foreach (int workItem in inputQueue)
{
int b= multiply(workItem);
data.Add(b);
Console.WriteLine("Worker {0} is processing item {1}." ,workerId,b);
Thread.Sleep(100); // Simulate work.
outputQueue.Add(workItem); // Output completed item.
}
Console.WriteLine("Worker {0} is stopping.", workerId);
}
void consumer()
{
Console.WriteLine("Consumer is starting.");
foreach (var workItem in outputQueue.GetConsumingEnumerable())
{
Console.WriteLine("Consumer is using item {0}", workItem);
Thread.Sleep(25);
}
Console.WriteLine("Consumer is finished.");
}
BlockingCollection<int> inputQueue = new BlockingCollection<int>();
BlockingCollection<int> outputQueue = new BlockingCollection<int>();
}
Is this what you're asking?
using System;
using System.Collections.Generic;
using System.Threading;
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>();
for (int i = 0; i <= 100; i++) { list.Add(i); }
foreach (int value in list)
{
Thread thread = new Thread(() => PrintNumberTimesFive(value));
thread.Start();
}
Console.ReadLine();
}
static void PrintNumberTimesFive(int number)
{
Console.WriteLine(number * 5);
}
}
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
When I execute this code in command line, it's working fine:
class Program
{
private static List<Ping> pingers = new List<Ping>();
private static List<string> value = new List<string>();
private static int instances = 0;
private static object #lock = new object();
private static int result = 0;
private static int timeOut = 2500;
private static int ttl = 7;
public static void Main()
{
string baseIP = "192.168.1.";
Console.WriteLine("Pinging destinations of D-class in {0}*", baseIP);
CreatePingers(254);
PingOptions po = new PingOptions(ttl, true);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data = enc.GetBytes("");
SpinWait wait = new SpinWait();
int cnt =1;
Stopwatch watch = Stopwatch.StartNew();
foreach (Ping p in pingers)
{
lock (#lock)
{
instances += 1;
}
p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeOut, data, po);
cnt += 1;
}
//while (instances > 0)
//{
// wait.SpinOnce();
//}
watch.Stop();
for (int i = 0; i < value.Count; i++)
{
Console.WriteLine(value[i]);
}
DestroyPingers();
Console.WriteLine("Finished in {0}. Found {1} active IP-addresses.", watch.Elapsed.ToString(), result);
Console.ReadKey();
}
public static void Ping_completed(object s, PingCompletedEventArgs e)
{
lock (#lock)
{
instances -= 1;
}
if (e.Reply.Status == IPStatus.Success)
{
string sa = string.Concat("Active IP: ", e.Reply.Address.ToString());
value.Add(sa);
//Console.WriteLine(sa);
String diachiip = e.Reply.Address.ToString();
result += 1;
}
else
{
//Console.WriteLine(String.Concat("Non-active IP: ", e.Reply.Address.ToString()))
}
}
private static void CreatePingers(int cnt)
{
for (int i = 1; i <= cnt; i++)
{
Ping p = new Ping();
p.PingCompleted += Ping_completed;
pingers.Add(p);
}
}
private static void DestroyPingers()
{
foreach (Ping p in pingers)
{
p.PingCompleted -= Ping_completed;
p.Dispose();
}
pingers.Clear();
}
}
But when I convert from it to window form, it doesn't work. I don't kwow why, I have tried many different ways...
Code is here:
public partial class Form1 : Form
{
public static List<Ping> pingers = new List<Ping>();
public static List<string> value = new List<string>();
public static int instances = 0;
public static object #lock = new object();
public static int result = 0;
public int timeout = 2500;
public static int ttl = 7;
public Form1()
{
InitializeComponent();
}
public void btnscan_Click(object sender, EventArgs e)
{
string baseIP = "192.168.1.";
//int kt = Int32.Parse(txtkt.Text);
//int start = Int32.Parse(txtstart.Text);
CreatePingers(254);
PingOptions po = new PingOptions(ttl, true);
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] data = enc.GetBytes("");
int cnt = 1;
Stopwatch watch = Stopwatch.StartNew();
foreach (Ping p in pingers)
{
lock (#lock)
{
instances += 1;
}
p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeout, data, po);
cnt += 1;
}
watch.Stop();
//Result alway return 0
lst1.Items.Add(result.ToString());
lst1.Items.Add(value.Count.ToString());
for (int i = 0; i < value.Count; i++)
{
lst1.Items.Add(value[i]);
lst1.Items.Add("\n");
}
DestroyPingers();
string a = "Finished in " + watch.Elapsed.ToString() + ". Found " + result + " active IP-addresses.";
lst1.Items.Add(a);
}
public static void CreatePingers(int kt)
{
for (int start = 1; start <= kt; start++)
{
// class System.Net.NetworkInformation.Ping
Ping p = new Ping();
p.PingCompleted += Ping_completed();
pingers.Add(p);
}
}
public static PingCompletedEventHandler Ping_completed()
{
PingCompletedEventHandler a = new PingCompletedEventHandler(abc);
return a;
}
static void abc(object s, PingCompletedEventArgs e)
{
value.Add("abc");
lock (#lock)
{
instances -= 1;
}
if (e.Reply.Status == IPStatus.Success)
{
string abcd = string.Concat("Active IP: ", e.Reply.Address.ToString());
value.Add(abcd);
result += 1;
}
}
public static void DestroyPingers()
{
foreach (Ping p in pingers)
{
p.PingCompleted -= Ping_completed();
p.Dispose();
}
pingers.Clear();
}
}
What is wrong in this code?
Method SendAsync returns 0 because you are not waiting for it to complete. You are missing await and async (see msdn):
async void btnscan_Click(object sender, EventArgs e)
{
...
await p.SendAsync(string.Concat(baseIP, cnt.ToString()), timeout, data,
...
}
SpinWait was making code to work in console application. In winforms you should not use SpinWait (nor Sleep) in UI thread. You can create another thread (e.g. by using Task) and then you can copy/paste code from console application 1-to-1. But then you will need to use Invoke each time when you want to access UI controls.
async/await is really better.. if it will work (I concluded that from method name, I've no idea what method does, nor how to use it).
Perhaps I miss one thing, if SendAsync returns value, then you can get it by (the requirement to mark method where you use await with async still):
var result = await p.SendAsync(...);
I have a function that reads numbers from console and writes them to queue and a massive of threads that should read numbers from queue, calculate factorials and write it to file.
static void Main(string[] args)
{
int threadsNumber = 0;
Console.WriteLine("Enter the number of threads: ");
while ((Int32.TryParse(Console.ReadLine(), out threadsNumber) == false)||(threadsNumber <= 0))
{
Console.WriteLine("You need to enter a positive number!");
}
Console.Clear();
Queue<int> numbersQueue = new Queue<int>();
Thread [] threadMas = new Thread[threadsNumber];
for (int i = 0; i < threadsNumber; i++)
{
threadMas[i] = new Thread(() => ThreadProc.ThreadProcStart(numbersQueue));
threadMas[i].Start();
}
//some code...
ThreadProc:
class ThreadProc
{
private static object locker = new object();
public static void ThreadProcStart(Queue<int> queue)
{
while (true)
{
int num = Deq(queue); //Checks if queue is empty. If not -
//Returns first element
if (num != -1)
{
BigInteger bigInt = Factorial.FactTree(num); //factorical
Writer.WriteToFile(num + " factorial: " + bigInt, "result.txt"); //write to file
}
else
{
// Here I need to add something
Thread.Sleep(0);
}
}
}
public static int Deq(Queue<int> queue)
{
lock (locker)
{
if (queue.Count != 0)
{
return queue.Dequeue();
}
return -1;
}
}
}
I need to stop all threads when all calculations are done. How can i mark thread as "unactive" when the queue is empty without actually aborting it?
Use BlockingCollection, which underneath the covers uses ConcurrentQueue. Your code will be soooo much simpler and you won't have to worry about subtle locking bugs.
Your code would then look something like this:
static void Main(string[] args)
{
int threadsNumber = 0;
Console.WriteLine("Enter the number of threads: ");
while ((Int32.TryParse(Console.ReadLine(), out threadsNumber) == false) || (threadsNumber <= 0))
{
Console.WriteLine("You need to enter a positive number!");
}
Console.Clear();
BlockingCollection<int> queue = new BlockingCollection<int>();
Thread[] threadMas = new Thread[threadsNumber];
for (int i = 0; i < threadsNumber; i++)
{
threadMas[i] = new Thread(ProcessQueue);
threadMas[i].Start(queue);
}
string userInput = null;
do
{
Console.WriteLine("Enter a number: ");
userInput = Console.ReadLine();
if (userInput != "stop") {
queue.Add(int.Parse(userInput)); // These numbers get process by the threads in parallel.
}
} while (userInput != "stop");
queue.CompleteAdding(); // Use this to signal that no more items will be added to the queue.
// Now the main thread exits.
// But the program stays alive until the other threads finish
// clearing the queue.
}
private static void ProcessQueue(object data)
{
BlockingCollection<int> queue = (BlockingCollection<int>)data;
foreach (var num in queue.GetConsumingEnumerable()) // This will automatically exit the loop once CompleteAdding is called and the queue is empty.
{
BigInteger bigInt = Factorial.FactTree(num); //factorical
Writer.WriteToFile(num + " factorial: " + bigInt, "result.txt"); //write to file
}
}
I have written a id manager for a xml repository. The repository manages entries in the xml file and assigns unique id (integers) to each entry that is added. The same way databases auto assign new id's to entries added to a table.
The repository will be called asynchronously so I need the id manager to be thread safe. I am using the C# lock statement but it does not seem to help. My unit tests succeed in single threaded execution but fail when run in parallel ( IE: Task ). Specifically they only fail with large sets of parallel tasks above 1000+ and even only then they only fail every other time.
The exception states that it expected 10000 but got 9998. The exception is always the same having to do with 2 missing id that were not registered.
What the heck am I missing?
ID Manager code and unit tests are provided below. The id manager utilizes Linq and is thus not very performance oriented with large sets of id's. Unit Tests TestAsyncRegistration and TestAsyncRandomRegistration are the tests that throw the exceptions.
public class IdManager
{
private List<int> idList = new List<int>();
private List<int> availableList = new List<int>();
private int nextId;
private int bufferCount;
object obj = new object();
public ReadOnlyCollection<int> RegisteredIds
{
get
{
return new ReadOnlyCollection<int>(this.idList);
}
}
public int BufferCount
{
get
{
return this.bufferCount;
}
set
{
if (value < 1)
{
throw new ArgumentOutOfRangeException("value");
}
this.bufferCount = value;
}
}
public IdManager(int bufferCount)
{
this.BufferCount = bufferCount;
this.Reset();
}
public IdManager()
: this(1000)
{
}
public void RegisterId(int id)
{
this.RegisterId(new[] { id });
}
public void Reset()
{
lock (this.obj)
{
this.availableList.Clear();
this.idList.Clear();
for (var i = 0; i < this.bufferCount; i++)
{
this.availableList.Add(i);
}
}
}
public void RegisterId(IEnumerable<int> ids)
{
lock (this.obj)
{
var distinct = ids.Except(this.idList);
this.idList.AddRange(distinct);
this.availableList = this.availableList.Except(this.idList).ToList();
}
}
public int NewId()
{
lock (this.obj)
{
if (this.availableList.Count > 0)
{
var item = this.availableList[0];
this.availableList.RemoveAt(0);
this.idList.Add(item);
return item;
}
var max = this.idList.Max();
for (var i = 1; i < this.bufferCount; i++)
{
this.availableList.Add(max + i);
}
this.availableList = this.availableList.Except(this.idList).ToList();
return this.NewId();
}
}
}
... and the unit test code ...
[TestClass]
public class IdManagerTests
{
[TestMethod]
public void TestSequence()
{
var manager = new IdManager(5);
for (var i = 0; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBrokenSequence()
{
var manager = new IdManager(5);
manager.RegisterId(1);
Assert.AreEqual(0, manager.NewId());
Assert.AreEqual(2, manager.NewId());
for (var i = 3; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestForwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(0);
manager.RegisterId(1);
manager.RegisterId(2);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public void TestBackwardSequence()
{
var manager = new IdManager(5);
manager.RegisterId(2);
manager.RegisterId(1);
manager.RegisterId(0);
Assert.AreEqual(3, manager.NewId());
Assert.AreEqual(4, manager.NewId());
for (var i = 5; i < manager.BufferCount + 10; i++)
{
Assert.AreEqual(i, manager.NewId());
}
}
[TestMethod]
public async Task TestLargeNumbersRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
manager.RegisterId(idValue++);
}
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
var manager = new IdManager(1000);
manager.RegisterId(list);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
[TestMethod]
public async Task TestAsyncRandomRegistration()
{
// register a list of id's from 0 to 1000
var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
list.Add(i);
}
// randomize the order of the id's in the list
var random = new Random((int)DateTime.Now.Ticks);
var randomizedList = from item in list
orderby random.Next()
select item;
var manager = new IdManager(1000);
manager.RegisterId(randomizedList);
var taskCount = 10000;
var taskList = new Task[taskCount];
var idValue = 0;
for (int i = 0; i < taskList.Length; i++)
{
taskList[i] = Task.Factory.StartNew(() => manager.RegisterId(idValue++));
}
Task.WaitAll(taskList);
Assert.AreEqual(taskCount, manager.NewId());
}
}
Your problem is in your test, not the method that you're testing, specifically the snippet:
Task.Factory.StartNew(() => manager.RegisterId(idValue++));
You're calling idValue++ from a bunch of different threads simultaneously. That's not a safe operation to perform. Either increment idValue outside of StartNew and pass in the already incremented value, or use Interlocked.Increment to handle it safely.
I am trying to do some filter task using TPL. Here I am simplifying the code to filter number based on condition. Here is the code.
public static void Main (string[] args)
{
IEnumerable<int> allData = getIntData ();
Console.WriteLine ("Complete Data display");
foreach (var item in allData) {
Console.Write(item);
Console.Write(" | ");
}
Console.WriteLine ();
filterAllDatas (ref allData, getConditions ());
foreach (var item in allData) {
Console.Write(item);
Console.Write(" | ");
}
Console.WriteLine ();
}
static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int,bool>> conditions)
{
List<int> filteredData = data.ToList ();
List<Task> tasks = new List<Task>();
foreach (var item in data.AsParallel()) {
foreach (var condition in conditions.AsParallel()) {
tasks.Add(Task.Factory.StartNew(() => {
if (condition(item)) {
filteredData.Remove(item);
}
}));
}
}
Task.WaitAll(tasks.ToArray());
data = filteredData.AsEnumerable ();
}
static IEnumerable<Func<int,bool>> getConditions()
{
yield return (a) => { Console.WriteLine("modulo by 2"); return a % 2 == 0;};
yield return (a) => { Console.WriteLine("modulo by 3"); Thread.Sleep(3000); return a % 3 == 0;};
}
static IEnumerable<int> getIntData ()
{
for (int i = 0; i < 10; i++) {
yield return i;
}
}
Here, it is simple code to filter out integer which is divided by two or three. Now, if I remove that thread sleep code work perfectly but if I put that it is not.
Normally means without Thread.Sleep , both condition execute 10 times e.g. for every number. But if I add Thread.Sleep first condition executes 7 times and second executes thirteen times. And because of this few number skip the condition. I try to debug but didn't get anything that can point out issue with my code.
Is there any good way to achieve this? Like filter condition on data can work async and parallel to improve performance ?
Code is for demo purpose only.
FYI: Currently I am using Mono with Xamarine studio on windows machine.
Please let me know if any further details needed.
I would guess it has to do with how your task's lambda closes over the loop variable condition. Try changing it as follows:
foreach (var condition in conditions.AsParallel()) {
var tasksCondition = condition
tasks.Add(Task.Factory.StartNew(() => {
if (tasksCondition(item)) {
filteredData.Remove(item);
}
}));
Note you're also closing over the loop variable item, which could cause similar problems.
First you can change your getConditions method to see what's happening inside :
static IEnumerable<Func<int, bool>> getConditions()
{
yield return (a) => { Console.WriteLine(a + " modulo by 2"); return a % 2 == 0; };
yield return (a) => { Console.WriteLine(a + " modulo by 3"); Thread.Sleep(3000); return a % 3 == 0; };
}
And if you stop capturing the foreach's variables, it will work :
static void filterAllDatas(ref IEnumerable<int> data, IEnumerable<Func<int, bool>> conditions)
{
List<int> filteredData = data.ToList();
List<Task> tasks = new List<Task>();
foreach (var item in data.AsParallel())
{
var i = item;
foreach (var condition in conditions.AsParallel())
{
var c = condition;
tasks.Add(Task.Factory.StartNew(() =>
{
if (c(i))
{
filteredData.Remove(i);
}
}));
}
}
Task.WaitAll(tasks.ToArray());
data = filteredData.AsEnumerable();
}
public class Program
{
static void Main(string[] args)
{
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(myThread.PrintName));
Thread t1 = new Thread(new ThreadStart(myThread.PrintType));
t.Start();
t1.Start();
Console.Read();
}
}
public class TestThread
{
public void PrintName()
{
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
}
public void PrintType()
{
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
}
}
Here How can i fixed it show that i can generate output in sequential i.e
first output of Name then only output of Type... Also I want to know about using Lock() in threads? where can i get good example. I am beginners in threading and need v.simple example.
Try this:
var myThread = new TestThread();
var x=Task.Factory.StartNew(() => myThread.PrintName());
x.ContinueWith(p => PrintType());
x.Wait();
You can look at this
There are multiple other articles, just google for 'introduction threading c#'.
The purpose of threads is to allow things to happen at the same time. If you want things to happen one after another (i.e. sequentially), then do not use threads:
var obj = new TestThread();
obj.PrintName();
obj.PrintType();
Console.Read();
Or put PrintName and PrintType into the same thread, in order to keep the UI responsive:
var myThread = new TestThread();
Thread t = new Thread(new ThreadStart(
() => {
myThread.PrintName(); myThread.PrintType();
}
));
t.Start();
// Do things in the UI meanwhile
for (i = 0; i < 100; i++) {
Console.WriteLine("UI thread {0}", i);
}
Console.Read();
//This will run two operation in sequence.
public class TestThread
{
public object obj = new object();
public void PrintName()
{
Monitor.Enter(obj);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
}
Monitor.Exit(obj);
}
public void PrintType()
{
Monitor.Enter(obj);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
}
Monitor.Exit(obj);
}
}
That will do the trick, you should read carefully and try to do it with 3 loops by yourself:
private static void SimpleLockTest()
{
Task[] myTasks = new Task[2];
myTasks[0] = Task.Factory.StartNew(() =>
{
LockTestThreadOne();
});
myTasks[1] = Task.Factory.StartNew(() =>
{
LockTestThreadTwo();
});
Task.WaitAll(myTasks);
Console.WriteLine("Done, press ENTER to quit");
Console.ReadLine();
}
private static object locker = new object();
private static void LockTestThreadOne()
{
Monitor.Enter(locker);
for (int i = 1; i <= 50; i++)
{
Console.WriteLine("Name {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker);
}
Monitor.Exit(locker);
}
private static void LockTestThreadTwo()
{
Monitor.Enter(locker);
for (int i = 100; i <= 180; i++)
{
Console.WriteLine("Type {0}", i);
Monitor.Pulse(locker);
Monitor.Wait(locker, 10);
}
Monitor.Exit(locker);
}