Return element from Thread - c#

I am trying to return element from Thread. And I have wrote this piece of code to do this. But my code sometime works correctly, but sometime not. Please help me to understand, what is wrong with this code. I am learning multi-threading in C#
Correct result
CorrectResultImage
Not correct
Not correect result image
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Thread_CallBack_Method
{
public delegate int CallBackDelegate(int sumofNumbers);
class Program
{
public static int Sum(int sum)
{
return sum;
}
static void Main(string[] args)
{
CallBackDelegate callback = new CallBackDelegate(Sum);
Numbers numbers = new Numbers(3, callback);
Thread t1 = new Thread(numbers.sumOfNumbers);
t1.Start();
Console.WriteLine("Sum of elements = {0} ",numbers.returnElementFromThread());
Console.ReadKey();
}
}
class Numbers
{
int _number;
CallBackDelegate _callBack;
public Numbers(int number, CallBackDelegate callback)
{
this._number = number;
this._callBack = callback;
}
int threadElement;
public void sumOfNumbers()
{
int sum = 0;
for (int i = 1; i <= _number; i++)
{
sum = sum + i;
}
if (_callBack != null)
threadElement = _callBack(sum);
}
public int returnElementFromThread()
{
return threadElement;
}
}
}

Because the thread is either completing before or after you print the result to the console. If you're going to have to wait for the result anyway, why are you bothering to use another thread?
Using threading is only useful when you want to perform operations simultaneously, or leave the UI responsive so the user doesn't get frustrated. What you have is a simple serial execution of code...using threading here isn't necessary.

Related

Access a while looped variable from a function that is running in thread and use in other function in C#

I am working on a complex project that is related to threading. Here is the simplest interpretation of my problem. Below is the code here are 3 functions excluding the main function. All functions are running in multi-threads. There is a while loop in all functions. I just want to get variable "i" and "k" from "func1" and "func2" respectively and use it in "func3". These variables are updated in the while loop.
This is the code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Threading
{
class Program
{
public static void func1() //How can I get the variable "i" from the while loop. Note: This function is running in thread.
{
int i = 1;
while (true)
{
Console.WriteLine("Func1: " + i);
i++;
}
}
public static void func2() //How can I get the variable "k" from the while loop. Note: This function is running in thread.
{
int k = 1;
while (true)
{
Console.WriteLine("Func2: " + k);
k++;
}
}
public static void func3() //After getting variables from func1 and func2 I want them to use in function 3.
{
while (true)
{
int sum = i + k;
Console.WriteLine("the sum is" + sum);
}
}
public static void Main(string[] args)
{
Thread t1 = new Thread(func1);
Thread t2 = new Thread(func2);
Thread t3 = new Thread(func3);
t1.Start();
t2.Start();
t3.Start();
}
}
}
You probably need to hoist the i and k from local variables to private fields of the Program class. Since these two fields will be accessed by more than one threads without synchronization, you should also declare them as volatile:
private static volatile int i = 1;
private static volatile int k = 1;
public static void func1()
{
while (true)
{
Console.WriteLine("Func1: " + i);
i++;
}
}
public static void func2()
{
while (true)
{
Console.WriteLine("Func2: " + k);
k++;
}
}
public static void func3()
{
while (true)
{
int sum = i + k;
Console.WriteLine("the sum is" + sum);
}
}
The pattern of access makes the use of volatile a bit wasteful though. The func1 is the only method that changes the i, so reading it with volatile semantics inside this method is pure overhead. You could use instead the Volatile.Read and Volatile.Write methods for finer control:
private static int i = 1;
private static int k = 1;
public static void func1()
{
while (true)
{
Console.WriteLine("Func1: " + i);
Volatile.Write(ref i, i + 1);
}
}
public static void func2()
{
while (true)
{
Console.WriteLine("Func2: " + k);
Volatile.Write(ref k, k + 1);
}
}
public static void func3()
{
while (true)
{
int sum = Volatile.Read(ref i) + Volatile.Read(ref k);
Console.WriteLine("the sum is" + sum);
}
}

Task and Background Worker thread safety, and Task Cancellation [duplicate]

This question already has answers here:
From Eric Lippert's blog: "don't close over the loop variable" [duplicate]
(4 answers)
Captured variable in a loop in C#
(10 answers)
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
I've made a real simple console app that I am using to break down a problem I am having on a larger application. I feel like I must have missed something in thread 101 class but I'm at a loss of what it is. Basically, the whole premise is to have a BackgroundWorker check on a timer a collection and then if another collection doesn't contain something from the first collection, start a new Task. If any anytime the Task isn't in running or created status, I want to cancel the task and create a new one.
The two behaviors I am noticing is one when there is an exception inside of the task, I am getting errors for Car Models that don't have an error (even though the task is new), and if I use a for loop my i iteration goes to 5 and the collection never has more than 4. I've also noticed that all 4 make an error at the same time, but I know there are some weird things with Random but I'm just not sure if that's the issue at this point.
If you want to see the for iteration go to 5, just use Y for the console readline, but this only happens in debug, running the application this doesn't seem to occur. The next thing I want to make sure of is that I am canceling the task properly.
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.ComponentModel;
using System.IO;
namespace ThreadTest
{
class Program
{
private static BackgroundWorker _backgroundWorker;
private static void _EstablishBackgroundWorker()
{
_backgroundWorker = new BackgroundWorker();
if (UseFor)
_backgroundWorker.DoWork += _UpdateCarsFor;
else
_backgroundWorker.DoWork += _UpdateCars;
Timer timer = new Timer(10000);
timer.Elapsed += _Timer_Elapsed;
timer.Start();
}
private static void _Timer_Elapsed(object sender, ElapsedEventArgs e)
{
while (_backgroundWorker.IsBusy)
{
}
if (!_backgroundWorker.IsBusy)
_backgroundWorker.RunWorkerAsync();
}
private static void _UpdateCarsFor(object sender, DoWorkEventArgs e)
{
string[] myCars = File.ReadAllLines(#"C:\cars\mycarfile.txt");
for (int i = 0; i < myCars.Length; i++)
if (!_cars.Where(x => x.Model == myCars[i].ToUpper()).Any())
_cars.Add(new Model.Car() { Model = myCars[i].ToUpper() });
for (int i = 0; i < _cars.Count; i++)
{
if (_cars[i].Task != null && _cars[i].Task.Status != TaskStatus.Running && _cars[i].Task.Status != TaskStatus.Created)
{
Console.WriteLine($"Making new task for { _cars[i].Model }");
_cars[i].tokenSource.Cancel();
_cars[i].RefreshToken();
_cars[i].Task = null;
}
if (_cars[i].Task == null)
{
_cars[i].Task = new Task(() => new Manufacture.Build().MakeCar(_cars[i].Model), _cars[i].cancellationToken);
_cars[i].Task.Start();
}
}
}
private static void _UpdateCars(object sender, DoWorkEventArgs e)
{
//string[] myCars = File.ReadAllLines(#"C:\cars\mycarfile.txt");
string[] myCars = new string[] { "F150", "RAM", "M3", "NSX" };
for (int i = 0; i < myCars.Length; i++)
if (!_cars.Where(x => x.Model == myCars[i].ToUpper()).Any())
_cars.Add(new Model.Car() { Model = myCars[i].ToUpper() });
foreach (var car in _cars)
{
if (car.Task != null && car.Task.Status != TaskStatus.Running && car.Task.Status != TaskStatus.Created)
{
Console.WriteLine($"Making new task for { car.Model }");
car.tokenSource.Cancel();
car.RefreshToken();
car.Task = null;
}
if (car.Task == null)
{
car.Task = new Task(() => new Manufacture.Build().MakeCar(car.Model), car.cancellationToken);
car.Task.Start();
}
}
}
private static List<Model.Car> _cars { get; set; }
private static bool UseFor { get; set; }
static void Main(string[] args)
{
_cars = new List<Model.Car>();
Console.WriteLine("Use for iteration? y/n");
var result = Console.ReadLine();
if (result.ToUpper() == "Y")
UseFor = true;
_EstablishBackgroundWorker();
Console.ReadLine();
}
}
}
Car.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ThreadTest.Model
{
class Car
{
public Car()
{
RefreshToken();
}
public string Model { get; set; }
public Task Task { get; set; }
public CancellationToken cancellationToken { get; set; }
public CancellationTokenSource tokenSource { get; set; }
public void RefreshToken()
{
tokenSource = new CancellationTokenSource();
cancellationToken = tokenSource.Token;
}
}
}
Build.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ThreadTest.Manufacture
{
class Build
{
public void MakeCar(string car)
{
try
{
while (true)
{
Random r = new Random();
int chaos = r.Next(0, 100);
Console.WriteLine($"Building {car}");
Thread.Sleep(2000);
if (chaos >= 90) throw new Exception($"Something went wrong with {car}");
}
}
catch(Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
throw;
}
}
}
}
Here is an example of all threads erroring at the same time, but even if i turn random down to a 1% chance this still happens.
All errors
In the comments with Henk, the mention of closing over the loop variable I don't believe applies because this method present a foreach and the issue of all threads erroring at the same time occurs, and the question of property canceling a task still remains.
private static void _UpdateCars(object sender, DoWorkEventArgs e)
{
//string[] myCars = File.ReadAllLines(#"C:\cars\mycarfile.txt");
string[] myCars = new string[] { "F150", "RAM", "M3", "NSX" };
for (int i = 0; i < myCars.Length; i++)
if (!_cars.Where(x => x.Model == myCars[i].ToUpper()).Any())
_cars.Add(new Model.Car() { Model = myCars[i].ToUpper() });
foreach (var car in _cars)
{
if (car.Task != null && car.Task.Status != TaskStatus.Running && car.Task.Status != TaskStatus.Created)
{
Console.WriteLine($"Making new task for { car.Model }");
car.tokenSource.Cancel();
car.RefreshToken();
car.Task = null;
}
if (car.Task == null)
{
car.Task = new Task(() => new Manufacture.Build().MakeCar(car.Model), car.cancellationToken);
car.Task.Start();
}
}
}

c# multiple threads waiting for a ManualResetEvent

I'm messing around with multithreading and making some sort of task engine. The idea is that the engine can have a configurable amount of threads waiting and when a new task arrives the first free thread picks it up and executes it.
The problem is that something 2 threads pickup the same task somehow. I looked it through and I think that this code should work but obviously it doesn't. If I add the 10ms sleep where it is now commented out it works, but I'm not sure I understand why. It looks like the .Reset() function returns before it actually resets the event?
Can somebody explain? Is there a better way to let only a single thread continue when there are multiple waiting?
Thanks
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace TaskTest
{
public class Engine
{
private ManualResetEvent taskEvent;
private ConcurrentQueue<Task> tasks;
private bool running;
private List<Thread> threads;
private int threadAmount;
private int threadsBusy = 0;
public Engine(int amountOfThreads)
{
taskEvent = new ManualResetEvent(false);
tasks = new ConcurrentQueue<Task>();
threads = new List<Thread>();
threadAmount = amountOfThreads;
}
public void Start()
{
running = true;
for (var i = 0; i < threadAmount; i++)
{
var thread = new Thread(Process);
thread.Name = "Thread " + i;
threads.Add(thread);
thread.Start();
}
}
public void Stop()
{
running = false;
taskEvent.Set();
threads.ForEach(t => t.Join());
}
private void Process()
{
while (running)
{
lock (taskEvent)
{
// Lock it so only a single thread is waiting on the event at the same time
taskEvent.WaitOne();
taskEvent.Reset();
//Thread.Sleep(10);
}
if (!running)
{
taskEvent.Set();
return;
}
threadsBusy += 1;
if (threadsBusy > 1)
Console.WriteLine("Failed");
Task task;
if (tasks.TryDequeue(out task))
task.Execute();
threadsBusy -= 1;
}
}
public void Enqueue(Task t)
{
tasks.Enqueue(t);
taskEvent.Set();
}
}
}
EDIT
Rest of the code:
namespace TaskTest
{
public class Start
{
public static void Main(params string[] args)
{
var engine = new Engine(4);
engine.Start();
while (true)
{
Console.Read();
engine.Enqueue(new Task());
}
}
}
}
namespace TaskTest
{
public class Task
{
public void Execute()
{
Console.WriteLine(Thread.CurrentThread.Name);
}
}
}
When using Console.Read() on a key press, two characters are read from the input. You should use Console.ReadLine() instead.
Note that your code can be simplified a lot by using a BlockingCollection to handle the synchronization:
public class Engine
{
private BlockingCollection<Task> tasks;
private List<Thread> threads;
private int threadAmount;
public Engine(int amountOfThreads)
{
tasks = new BlockingCollection<Task>();
threads = new List<Thread>();
threadAmount = amountOfThreads;
}
public void Start()
{
for (var i = 0; i < threadAmount; i++)
{
var thread = new Thread(Process);
thread.Name = "Thread " + i;
threads.Add(thread);
thread.Start();
}
}
public void Stop()
{
tasks.CompleteAdding();
threads.ForEach(t => t.Join());
}
private void Process()
{
foreach (var task in tasks.GetConsumingEnumerable())
{
task.Execute();
}
}
public void Enqueue(Task t)
{
tasks.Add(t);
}
}

use multithread to write into text files using C#

Hope you can help me with this one.i am beginner in multithreading programming with C#.
I am trying to build a program to write all numbers from range 1 to 2000 in two text files using two threads.
Every thread should write number from 1 to 2000 that not found at any of the two files "there is no duplicated numbers in the files" and every thread should't write the number that have been wrote by the another thread.
At the end if we merged the numbers of the two files we should have the numbers from 1 to 2000
Here is the source code i am trying but there is a problem in the writing for loop in the below image
i can't handle the process of writing by the two synchronized threads and i had exception:
Object synchronization method was called from an unsynchronized block of code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
namespace Multithreading
{
class Program
{
static TextWriter file2 = new StreamWriter("file2 location");
static TextWriter file1 = new StreamWriter("file1 location");
static void Main(string[] args)
{
try
{
int[] array = new int[2000];
Thread thread1 = new Thread(Program.writeinfile1);
Thread thread2 = new Thread(Program.writeinfile2);
for (int counter = 1; counter <= 2000; counter++)
{
thread1.Start(counter);
thread2.Start(++counter);
Monitor.Enter(thread1);
Monitor.Wait(thread1);
Monitor.PulseAll(thread2);
}
}
catch (FileNotFoundException)
{
Console.WriteLine("the file you are trying to open is not found");
}
}
public static void writeinfile1(object x)
{
int converttointx = (int)x;
file1.WriteLine(converttointx);
file1.Close();
}
public static void writeinfile2(object y)
{
int converttointy = (int)y;
file2.WriteLine(converttointy);
file2.Close();
}
}
}
Here's an example of multi-threaded calls talking to one another to ensure they don't duplicate work.
I've not done exactly what you've asked for, since this looks quite homeworky; but hopefully this will help you to figure out the solution to your issue...
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
new Program();
Console.WriteLine("done");
Console.ReadKey();
}
Program()
{
int noThreads = 5;
int target = 2000;
StartThread(noThreads, target);
}
//kicks off our threads / waits for all threads to complete before returning
void StartThread(int noThreads, int target)
{
int id = noThreads--;
if (id > 0)
{
Doer doer = new Doer(id, target);
Thread t = new Thread(doer.Do);
t.Start();
StartThread(noThreads,target);
t.Join();
}
}
}
class Doer
{
static int marker = 0;
static readonly object syncLocker = new object();
readonly int id;
readonly int target;
public Doer(int id, int target)
{
this.id = id;
this.target = target;
}
public void Do()
{
while (marker < this.target)
{
int i;
lock (syncLocker)
{
i = ++marker;
}
System.Console.WriteLine("{0:00}: {1:###0}", id, i);
//Thread.Sleep(RandomNo()); //uncomment this & code below if your threads are taking turns / behaving too predictably
}
}
/*
static readonly Random rnd = new Random();
static readonly object rndSyncLocker = new object();
public static int RandomNo()
{
lock (rndSyncLocker)
{
return rnd.Next(0, 1000);
}
}
*/
}
}
You are not using the Monitor class correctly. The call to Monitor.PulseAll(thread2); should be called within thread the thread which owns the lock, which in this case would be within the writeinfile1 and writeinfile2 method.
This is why you are getting the exception:
Object synchronization method was called from an unsynchronized block of code.
See the following StackOverflow question for the correct way to use Monitor.PulseAll(object):
Help needed in Monitor.PulseAll()

Duplicate Logon Script

ok, so I'm writing a duplicate logon "worker" class in C# and I've ran into a bit of a snag. My logic behind it, I thought, was flawless! :(
But, I can't for the life of me figure out why it's triggering on the first occurence rather than on just duplicates :(
namespace Lab.Core.BackgroundWorker {
using Lab.Core;
using Lab.Core.Net;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
public class MultiLogon : IWorker {
private static Hashtable LoggedOnUsers = new Hashtable();
private Thread _worker = null;
//private Thread m_UsersUpdate = null;
public delegate Boolean AddUserToCollectionDelegate(String user, String computer);
public delegate void ClearCollectionDelegate(String user);
public delegate Boolean IsUserLoggedInDelegate(String user);
public Boolean AddUserToCollection(String user, String computer) {
int retVal = MultiLogon.LoggedOnUsers.Count + 1;
if (String.IsNullOrEmpty(user) || String.IsNullOrEmpty(computer))
return false;
if (!MultiLogon.LoggedOnUsers.ContainsKey(user))
MultiLogon.LoggedOnUsers.Add(user, computer);
return (MultiLogon.LoggedOnUsers.Count == retVal);
}
public void ClearCollection() {
if (MultiLogon.LoggedOnUsers.Count > 0)
MultiLogon.LoggedOnUsers.Clear();
}
public Boolean IsUserLoggedIn(String user) {
if (String.IsNullOrEmpty(user))
return false;
return (LoggedOnUsers.Contains(user));
}
#region IWorker Members
public void Run(object obj) {
AddUserToCollectionDelegate add = new AddUserToCollectionDelegate(AddUserToCollection);
//ClearCollectionDelegate clear = new ClearCollectionDelegate(ClearCollection);
//IsUserLoggedInDelegate isLogged = new IsUserLoggedInDelegate(IsUserLoggedIn);
while (true) {
foreach (Computer c in ComputerList.Instance)
if (!add.Invoke(c.UserName, c.MachineName)) {
// duplicate! or not? :/
// Credit (through adoption of code) goes to:
// http://bytes.com/groups/net-c/263778-quickly-finding-duplicates-arraylist#post1059834
foreach (DictionaryEntry item in MultiLogon.LoggedOnUsers) {
MessageBox.Show((String)item.Key, (String)item.Value);
//NetworkMessage.Send((String)item.Value, String.Format("It is against lab policy to share your account with anyone other than yourself or use someone else's account! Logout immediately or further action will be taken. Your action has been logged."));
//OffenseManager.Instance.AddOffense((String)item.Key, null, String.Format("Account sharing - Computer: {0}", item.Value), false);
}
}
Thread.Sleep(750);
}
}
public void Start() {
_worker = new Thread(new ParameterizedThreadStart(Run));
_worker.IsBackground = true;
_worker.Start();
}
public void Stop() {
if (_worker.IsAlive)
_worker.Abort();
}
#endregion
}
}
Apologies for the long code file. I don't know exactly what to paste to help you guys help me. :/
Thanks in advance! :)
Could be a thread race condition.
Have you tried to lock the collection when you're searching/inserting into it?
I don't believe Hashtable are threadsafe.
You might want to put a
lock(this) {
}
block around anything accessing the hashtable.

Categories