Query inside a thread - c#

I have 3 comboboxes that are loaded with data from LINQ queries on page load. The problem is that queries contain so much data that it causes Internet Explorer to stop responding for a bit more than a minute.
As there are 3 queries my idea is to put them in 3 different threads, but the problem is at the end the only thing I get is the error saying: "Both DataSource and DataSourceID are defined on 'cbOrganizator'. Remove one definition."
cbOrganizator is a combobox.
Here is the code:
protected void Page_Load(object sender, EventArgs e)
{
Bind();
}
public void Osobe()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var osoba = from o in db.osobas
orderby o.osoba_prezime
select new { o.osoba_id, imePrezime = o.osoba_prezime + " " + o.osoba_ime + " | " + o.tijelo.tijelo_naziv + " | " + o.radno_mjesto.rm_naziv_m };
cbPolaznik.DataSource = osoba;
cbPolaznik.DataTextField = "imePrezime";
cbPolaznik.DataValueField = "osoba_id";
cbPolaznik.DataBind();
cbPolaznik.Items.Insert(0, " ");
cbPredavac.DataSource = osoba;
cbPredavac.DataTextField = "imePrezime";
cbPredavac.DataValueField = "osoba_id";
cbPredavac.DataBind();
cbPredavac.Items.Insert(0, " ");
cbAOM.DataSource = osoba;
cbAOM.DataTextField = "imePrezime";
cbAOM.DataValueField = "osoba_id";
cbAOM.DataBind();
cbAOM.Items.Insert(0, " ");
}
public void Tijela()
{
PravosudnaAkademijaEntities db = new PravosudnaAkademijaEntities();
var tijelo = from t in db.tijeloes
orderby t.tijelo_naziv
select new { t.tijelo_id, sve = t.tijelo_naziv + " | " + t.mjesto.zupanija_drzava.zupanija_naziv };
cbOrganizator.DataSource = tijelo;
cbOrganizator.DataTextField = "sve";
cbOrganizator.DataValueField = "tijelo_id";
cbOrganizator.DataBind();
cbOrganizator.Items.Insert(0, " ");
}
public void Bind()
{
Thread tOsobe = new Thread(Osobe);
tOsobe.Start();
Thread tTijela = new Thread(Tijela);
tTijela.Start();
}
I don't know what's wrong so any help would be appreciated. The primary idea is to separate queries into threads so if my approach is wrong please let me know.

You're starting threads but not giving them a chance to finish before the page is loaded. I don't know how that results in your particular error, but if your page loads before the thread is completed, then you definitely won't get results.
I really don't see how you'll be able to accomplish what you're trying to do without AJAX.

if you do really want to do it with threads i would suggest performing the query on the threadpool. you can abstract your method so that it is called in delegate of the threadpool method
so i would replace bind with
ThreadPool.QueueUserWorkItem(new WaitCallback(Osobe));
ThreadPool.QueueUserWorkItem(new WaitCallback(Tijela));
change signature of Osobe, and Tijela to acccept a Object
eg.public void Osobe(object a )
you will also need to marshal the call across the thread as i am not sure if webforms will accept if the binding is happening on another thread.
All said and done is still feel the ajax method is the best way forward.

Related

C# static function is sending wrong arguments to function

My code is passing the wrong argument to a function for some reason.
I have a static class say class A having this function AddMaster :
public static void AddMaster(string ipAddress, int port, List<RegisterMap> registers)
{
// THIS LINE PRINTS THE ACTUAL VALUES SENT FROM THE CALLER FUNCTION
System.IO.File.AppendAllText("datalog_MB.txt", ipAddress + " " + registers[0].FriendlyName + "\n");
new Thread(() =>
{
_tasks.Add(Task.Factory.StartNew(() =>
{
Monitor.Enter(_masters);
_masters.Add(new Master().Connect(ipAddress, port).SetRegisters(registers));
_masters.Last().OnEvent += MasterEvent;
Debug.WriteLine(_masters.Count + " TCP masters connected");
Monitor.Exit(_masters);
}));
}).Start();
}
I have another non-static class Master having the function SetRegisters:
public Master SetRegisters(List<RegisterMap> registerList)
{
// HERE THE FriendlyName ALWAYS PRINTS THE VALUE OF THE LAST FUNCTION CALL
System.IO.File.AppendAllText("datalog_MB_1.txt", _hostname + " " + registerList[0].FriendlyName + "\n");
_registersToRead = registerList;
return this;
}
The function AddMaster() is called in a loop.
The first code logs the following which is correct:
# datalog_MB.txt
192.168.0.12 192.168.0.12:Value 1
192.168.0.11 192.168.0.11:Value 1
However the second code block prints the following ( See the second value has changed ):
# datalog_MB_1.txt
192.168.0.12 192.168.0.11:Value 1
192.168.0.11 192.168.0.11:Value 1
Edit #1
foreach (var equipment in MSSQL.GetEquipments(true))
{
registers.Clear();
System.IO.File.AppendAllText("dataeq.txt", equipment.IPAddress + " " + equipment.Name + " " + equipment.ID + "\n");
try
{
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 1",
Register = 2001,
Type = RegisterType.HoldingRegister,
StationID = 1
});
registers.Add(
new RegisterMap
{
FriendlyName = equipment.IPAddress + ":Value 2",
Register = 2002,
Type = RegisterType.HoldingRegister,
StationID = 1
});
A.AddMaster(equipment.IPAddress, 502, registers);
var json = new JavaScriptSerializer().Serialize(registers);
System.IO.File.AppendAllText("data_reg.txt", json + "\n\n");
}
catch(Exception err)
{
System.Windows.MessageBox.Show(err.Message);
}
}
Edit #2*
Fiddle: https://dotnetfiddle.net/h3yn7p
Any idea what might be going wrong?
You should not Clear the registers - recreate it:
List<RegisterMap> registers = null;
foreach(var equipment in equipments)
{
registers = new List<RegisterMap>();
....
}
Otherwise you are processing the same instance of List<RegisterMap> in parallel in multiple threads while manipulating it (i.e. thread which has the foreach(var equipment in equipments) loop will run and create all the threads and start them), which can lead to a lot of different concurrency issues.
Also some notes:
Consider using concurrent collections, for example ConcurrentBag<T> instead of Monitor + List (cause in current code it makes Thread/Task handling pointless)
Based on the provided code there is no need to create Thread - tasks should be enough. In modern .NET there is rarely a case when you need to create Threads manually, most of the time it is hugely discouraged (read more).

Update console text from multiple threads not working

I am executing/processing very big files in multi threaded mode in a console app.
When I don't update/write to the console from threads, for testing the whole process take about 1 minute.
But when I try to update/write to console from threads to show the progress, the process stuck and it never finishes (waited several minutes even hours). And also console text/window does not updated as it should.
Update-1: As requested by few kind responder, i added minimal code that can reproduce the same error/problem
Here is the code from the thread function/method:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Large_Text_To_Small_Text
{
class Program
{
static string sAppPath;
static ArrayList objThreadList;
private struct ThreadFileInfo
{
public string sBaseDir, sRFile;
public int iCurFile, iTFile;
public bool bIncludesExtension;
}
static void Main(string[] args)
{
string sFileDir;
DateTime dtStart;
Console.Clear();
sAppPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
sFileDir = #"d:\Test";
dtStart = DateTime.Now;
///process in multi threaded mode
List<string> lFiles;
lFiles = new List<string>();
lFiles.AddRange(Directory.GetFiles(sFileDir, "*.*", SearchOption.AllDirectories));
if (Directory.Exists(sFileDir + "-Processed") == true)
{
Directory.Delete(sFileDir + "-Processed", true);
}
Directory.CreateDirectory(sFileDir + "-Processed");
sPrepareThreading();
for (int iFLoop = 0; iFLoop < lFiles.Count; iFLoop++)
{
//Console.WriteLine(string.Format("{0}/{1}", (iFLoop + 1), lFiles.Count));
sThreadProcessFile(sFileDir + "-Processed", lFiles[iFLoop], (iFLoop + 1), lFiles.Count, Convert.ToBoolean(args[3]));
}
sFinishThreading();
Console.WriteLine(DateTime.Now.Subtract(dtStart).ToString());
Console.ReadKey();
return;
}
private static void sProcSO(object oThreadInfo)
{
var inputLines = new BlockingCollection<string>();
long lACounter, lCCounter;
ThreadFileInfo oProcInfo;
lACounter = 0;
lCCounter = 0;
oProcInfo = (ThreadFileInfo)oThreadInfo;
var readLines = Task.Factory.StartNew(() =>
{
foreach (var line in File.ReadLines(oProcInfo.sRFile))
{
inputLines.Add(line);
lACounter++;
}
inputLines.CompleteAdding();
});
var processLines = Task.Factory.StartNew(() =>
{
Parallel.ForEach(inputLines.GetConsumingEnumerable(), line =>
{
lCCounter++;
/*
some process goes here
*/
/*If i Comment out these lines program get stuck!*/
//Console.SetCursorPosition(0, oProcInfo.iCurFile);
//Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
});
});
Task.WaitAll(readLines, processLines);
}
private static void sPrepareThreading()
{
objThreadList = new ArrayList();
for (var iTLoop = 0; iTLoop < 5; iTLoop++)
{
objThreadList.Add(null);
}
}
private static void sThreadProcessFile(string sBaseDir, string sRFile, int iCurFile, int iTFile, bool bIncludesExtension)
{
Boolean bMatched;
Thread oCurThread;
ThreadFileInfo oProcInfo;
Salma_RecheckThread:
bMatched = false;
for (int iTLoop = 0; iTLoop < 5; iTLoop++)
{
if (objThreadList[iTLoop] == null || ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == false)
{
oProcInfo = new ThreadFileInfo()
{
sBaseDir = sBaseDir,
sRFile = sRFile,
iCurFile = iCurFile,
iTFile = iTFile,
bIncludesExtension = bIncludesExtension
};
oCurThread = new Thread(sProcSO);
oCurThread.IsBackground = true;
oCurThread.Start(oProcInfo);
objThreadList[iTLoop] = oCurThread;
bMatched = true;
break;
}
}
if (bMatched == false)
{
System.Threading.Thread.Sleep(250);
goto Salma_RecheckThread;
}
}
private static void sFinishThreading()
{
Boolean bRunning;
Salma_RecheckThread:
bRunning = false;
for (int iTLoop = 0; iTLoop < 5; iTLoop++)
{
if (objThreadList[iTLoop] != null && ((System.Threading.Thread)(objThreadList[iTLoop])).IsAlive == true)
{
bRunning = true;
}
}
if (bRunning == true)
{
System.Threading.Thread.Sleep(250);
goto Salma_RecheckThread;
}
}
}
}
And here is the screenshot, if I try to update console window:
You see? Nor the line number (oProcInfo.iCurFile) or the whole line is correct!
It should be like this:
1 = xxxxx
2 = xxxxx
3 = xxxxx
4 = xxxxx
5 = xxxxx
Update-1: To test just change the sFileDir to any folder that has some big text file or if you like you can download some big text files from following link:
https://wetransfer.com/downloads/8aecfe05bb44e35582fc338f623ad43b20210602005845/bcdbb5
Am I missing any function/method to update console text from threads?
I can't reproduce it. In my tests the process always runs to completion, without getting stuck. The output is all over the place though, because the two lines below are not synchronized:
Console.SetCursorPosition(0, oProcInfo.iCurFile);
Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
Each thread of the many threads involved in the computation invokes these two statements concurrently with the other threads. This makes it possible for one thread to preempt another, and move the cursor before the first thread has the chance to write in the console. To solve this problem you must add proper synchronization, and the easiest way to do it is to use the lock statement:
class Program
{
static object _locker = new object();
And in the sProcSO method:
lock (_locker)
{
Console.SetCursorPosition(0, oProcInfo.iCurFile);
Console.Write(oProcInfo.iCurFile + " = " + lCCounter.ToString());
}
If you want to know more about thread synchronization, I recommend this online resource: Threading in C# - Part 2: Basic Synchronization
If you would like to hear my opinion about the code in the question, and you don't mind receiving criticism, my opinion is that honestly the code is so much riddled with problems that the best course of action would be to throw it away and restart from scratch. Use of archaic data structures (ArrayList???), liberal use of casting from object to specific types, liberal use of the goto statement, use of hungarian notation in public type members, all make the code difficult to follow, and easy for bugs to creep in. I found particularly problematic that each file is processed concurrently with all other files using a dedicated thread, and then each dedicated thread uses a ThreadPool thread (Task.Factory.StartNew) to starts a parallel loop (Parallel.ForEach) with unconfigured MaxDegreeOfParallelism. This setup ensures that the ThreadPool will be saturated so badly, that there is no hope that the availability of threads will ever match the demand. Most probably it will also result to a highly inefficient use of the storage device, especially if the hardware is a classic hard disk.
Your freezing problem may not be C# or code related
on the top left of your console window, on the icon .. right click
select Properties
remove the option of Quick Edit Mode and Insert Mode
you can google that feature, but essentially manifests in the problem you describe above
The formatting problem on the other hand does seem to be, here you need to create a class that serializes writes to the console window from a singe thread. a consumer/producer pattern would work (you could use a BlockingCollection to implement this quite easily)

having trouble with a timer in C# code

I'm having issues implementing a timer in C# code. high level overview of what I'm doing, i have a WPF app that updates data displayed to the user every three seconds based on a data feed. Most of the data on the window changes every three seconds but I'm trying to do an SQL query for a count and i only want the data to update every 5 minutes. So I built the SQL query shown below and the timer also shown below but the timer expects it to be a void when it had to return a string and i'm not sure how to get past this.
My original attempt at using a Timer (this runs in my main method):
Timer t = new Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); // set the time (5 min in this case)
t.AutoReset = true;
t.Elapsed += new System.Timers.ElapsedEventHandler(SQLDataTotalCalls());
t.Start();
My Method for the SQL Query:
public string SQLDataTotalCalls(object sender, ElapsedEventArgs a)
{
DateTime dte = DateTime.Today;
string fixedStartDate = String.Format("{0:yyyy-MM-dd " + "05:00:00.000" + "}", dte);
string fixedEndDate = String.Format("{0:yyyy-MM-dd " + "05:00:00.000" + "}", dte.AddDays(1));
SqlConnection connection = null;
try
{
var dataSet = new DataSet();
connection = new SqlConnection("Data Source=QL1OADB1;Initial Catalog=OADB;User Id=username;Password=password;
connection.Open();
var command = new SqlCommand("SELECT COUNT(SOURCEID) AS 'MYCOUNT' "
+ "FROM [OADB].[oadb].[CmsCallHistory] "
+ "WHERE disposition = 2 and DISPSPLIT in (" + SkillNumber + ") AND SEGSTOP BETWEEN '" + fixedStartDate + "' and '" + fixedEndDate + "'",
connection)
{
CommandType = CommandType.Text
};
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataSet);
return dataSet.Tables[0].Rows[0]["MYCOUNT"].ToString();
}
catch (Exception e)
{
throw new Exception(e.Message, e);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
}
Update:
Per the suggested answer below, I've changed the above to this:
async Task RunPeriodicQueryTotalCalls()
{
TimeSpan interval = TimeSpan.FromMinutes(5);
while (true)
{
await Task.Delay(interval);
string result = await Task.Run(SQLDataTotalCalls);
TotalDailyCalls = result;
}
}
I've updated my method for the SQL Query to have this declaration:
public string SQLDataTotalCalls() { ... }
But I get a compiler error:
error CS0121: The call is ambiguous between the following methods or properties: 'Task.Run<TResult>(Func<TResult>)' and 'Task.Run(Func<Task>)'
Supposing C# would let you subscribe your string-returning method to the void-declared event. What code, exactly, do you think would actually be receiving that return value? Where would you use it?
There isn't much context in your question, which makes it difficult, if not impossible, to understand exactly what you want the code to do. There's nothing in your question that indicates how you'd get the returned string value, nor what you'd do with it.
All that said, I think it likely your needs are better served using the Task Parallel Library API instead of a timer. This will allow you to easily move return values from background task to UI thread, as well as handle the timing for you.
For example:
async Task RunPeriodicQuery()
{
TimeSpan interval = TimeSpan.FromMinutes(5);
while (true)
{
await Task.Delay(interval);
string result = await Task.Run((Func<string>)SQLDataTotalCalls);
// do something with "result" here...you'll be in the UI thread, so make it quick
}
}
In the above, you would remove the parameters from your SQLDataTotalCalls() method declaration.
You will need to call the method RunPeriodicQuery() once, in some part of your code where you are initializing and would have otherwise created and started the timer. The implementation above uses an inifite while (true) loop, but of course you can introduce any mechanism you want to allow the method to exit if and when you want it to stop operating, such as using a bool field instead of true to control the loop operation.
If that does not address your question satisfactorily, please improve the question by editing it so that it includes a good Minimal, Complete, and Verifiable code example that shows clearly what you've tried, explain precisely what the code does, and what you want it to do instead.
Your code is calling the method, rather than pointing the event to your method.
// notice there are no parens, that's because you are pointing it at a method, not running the method
t.Elapsed += new System.Timers.ElapsedEventHandler(SQLDataTotalCalls);
A simpler way of doing this is:
t.Elapsed += SQLDataTotalCalls;
The timer should only be used to fire an event, not return a value. What is done in the event delegate (SQLDataTotalCalls) should pass the string to some other object or service to save the string.
You will need to change the signature of your SQLDataTotalCalls method to return void, so that it will match the signature required for the timer handler

C# Getter-Setter Race Conditions

Suppose I have two threads, thread A and thread B. What happens in C# when thread A sets an object, call it object X, to a value, and thread B comes along and tries to fetch that object while it is getting set by thread A? Would C# throw an exception, would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
I thought it was clear, but here is the code (and even with added synchronization I am still not 100% sure that this would cause the exact case I mentioned above to occur):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication8 {
public partial class Form1 : Form {
private AutoResetEvent waitEvent = new AutoResetEvent(false);
int objectX = 0;
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e) {
DateTime startTime = DateTime.Now;
Console.WriteLine("---------------------------- START # " + startTime + " ----------------------------------------------------------------------");
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
objectX = 0;
waitEvent = new AutoResetEvent(false);
A.Start();
B.Start();
A.Join();
B.Join();
Console.WriteLine("---------------------------- FINISHED AFTER " + (DateTime.Now - startTime).TotalMilliseconds + " ----------------------------");
}
public void ThreadAWorkMethod() {
waitEvent.WaitOne();
objectX = 5;
Console.WriteLine("Value has been changed to: " + objectX + " in thread A at " + DateTime.Now);
return;
}
public void ThreadBWorkMethod() {
waitEvent.Set();
string xInThreadB = objectX.ToString();
Console.WriteLine("Value in thread B: " + xInThreadB + " at " + DateTime.Now);
return;
}
}
}
The output of thread B to the console looks to be either 0 or 5, but even still you cannot say for certain which thread got serviced first even by checking the DateTime because both threads will have identical timestamps...and one output always makes it to the console first, so whose to say which got serviced first and if the threads actually collided on a get-set. So, in the end it seems that locking is implemented on variables in C# from a lower framework level as some people have mentioned.
Would C# throw an exception
No, it will likely not. There is nothing in the runtime that will check for this condition automatically and raise an exception.
However, the "value" being set may or may not be in a valid state at that point, so as soon as the result is used, whatever uses the value could easily raise an exception.
would B receive object X before A makes changes to it, or would B receive object X after A makes changes to it?
Either is possible. It's also possible, depending on the type of "object", that B would receive the object in an invalid state.
If you know multiple threads will be accessing a value, you should always take care to synchronize the access to your property. There are many options for synchronization, from using the (relatively) simple lock statement to other more complex synchronization options (such as ReaderWriterLock/ReaderWriterLockSlim, Mutex, Semaphore, etc).
So, something like this?
public class Test
{
public Test()
{
DateTime now = DateTime.Now;
Debug.WriteLine("Test started.");
A.Start();
B.Start();
A.Join();
B.Join();
Debug.WriteLine("Total time, in milliseconds, that you just spent in order to save StackOverflow members several minutes of their time: " + (DateTime.Now - now).TotalMilliseconds + " :)");
}
int objectX = 0;
Thread A = new Thread(ThreadAWorkMethod);
Thread B = new Thread(ThreadBWorkMethod);
public void ThreadAWorkMethod()
{
objectX = 5;
Debug.WriteLine("Value has been changed to: " + objectX.ToString() + "at " DateTime.Now.Milliseconds);
return;
}
public void ThreadBWorkMethod()
{
string xInThreadB = objectX.ToString();
Debug.WriteLine("Value in thread b: " + xInThreadB + "at " DateTime.Now.Milliseconds);
return;
}
}
I dunno, try it :)
Potentially similar question to C# Threading: a race condition example.
PS: That's why there is the lock and mutex in .NET Framework.

Multi-threading for overload and thread name is empty

This situation might seem strange but this is what i have to do:
Situation, i have a sharepoint portal and there was such an issue that there might be a problem while retrieving user profiles that there might be too slow when a lot of people online and perfrom that kind of action, so there was made a descision to make a console application to test it out.
The console application needs to simulate behavior for retrieving the user profiles with as if many different users are doing that.
And there must be a log written.
The first question is this kind of testing a good way to really know where exactly the problme is?
And the other question is about my application, i have a strange behavior:
public class Program
{
static void Main(string[] args)
{
string filePath = #"C:\Users\User\Desktop\logfile.txt";
string siteUrl = #"http://siteurl";
int threads = 1;
//Multiplicator multiplicator = new Multiplicator(filePath, siteUrl, threads);
//Console.ReadLine();
for (int i = 0; i < 100; i++)
{
Thread t = new Thread(Execute);
t.Start();
}
Console.WriteLine("Main thread: " + Thread.CurrentThread.Name);
// Simultaneously, do something on the main thread.
}
static void Execute()
{
for (int i = 0; i < 100; i++)
{
using (SPSite ospSite = new SPSite(#"http://siteurl"))
{
SPServiceContext serviceContext = SPServiceContext.GetContext(ospSite);
UserProfileManager profileManager = new UserProfileManager(serviceContext);
UserProfile userProfile = profileManager.GetUserProfile("User Name");
string message = "Retrieved: " + userProfile.DisplayName + " on " +DateTime.Now + "by " Thread.CurrentThread.Name;
Console.WriteLine(message);
}
}
}
}
So the problem is i never get the name of the thread written why?
Thread.CurrentThread.Name is empty, is it normal, maybe i initialize the threading wrong? Altho many sources said that it is done like this?
You have not set the name of the thread. You should do so before you start it, and you can incorporate the iteration number in the name, if you like:
Thread t = new Thread(Execute);
t.Name = "My Thread" + i.ToString();
t.Start();
They are not given names automatically. The name can only be set once, after which you would get an InvalidOperationException
MSDN Reference: Thread.Name
Incidentally, creating 100 threads is probably not a good idea under normal circumstances.
You need to give it a name. Just when you create the thread, just name it based on i
Thread t = new Thread(Execute) { Name = i.ToString() };
Ok, I will go for your first question. No, there is a better way to do this.
Put the site under load. Maybe a friend can hit F5 all the time or you run a batch file with 1000 lines of a curl get
Attach the Visual Studio debugger to the webserver process
Hit break 10 times and see where it stops most of the time. That is your hotspot/problem.
This is called the poor mans profiler. It is built into every Visual Studio ;-)
In general, it is easy to find such problems by doing profiling. There are even sophisticated tools for this.

Categories