Thread safety in parameters passed to a static method - asp.net

Assuming a static method like below is called from ASP.NET page,
can a different thread(b) overwrite the value of s1 after the first line is executed by thread(a)?
If so, can assigning parameters to local variables before manipulation solve this?
public static string TestMethod(string s1, string s2, string s3)
{
s1 = s2 + s3;
....
...
return s1;
}
Is there are a simple way to recreate such thread safety related issues?
Thanks.

No, the parameters are local variables - they're independent of any other threads. As strings are also immutable, you're safe. If these were mutable - e.g. a parameter of StringBuilder s1 - then although the value of s1 (a reference) couldn't be changed, the object that the parameter referred to could change its contents.
ref and out parameters could potentially have issues, as they can alias variables which are shared between threads.

I had same confusion too and here is my test code. Just sharing it ...
public partial class _default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ThreadTest b = new ThreadTest();
Thread t = new Thread(new ParameterizedThreadStart(ThreadTest.sum));
Thread t1 = new Thread(new ParameterizedThreadStart(ThreadTest.sum));
t.Start(10);
t1.Start(12);
}
}
class ThreadTest
{
public static void sum(object XX)
{
int x = (int)XX;
for (int i = 0; i < x; i++)
{
System.Diagnostics.Debug.WriteLine("max : " + x + " --- " + i.ToString());
}
}
}
... Now if you run this you will see that int x is safe. so local non static variables are safe for a process and can not crippled by multiple thread

Yes, under some condition, as seen by the example code.
public static class ConsoleApp {
public static void Main() {
Console.WriteLine("Write something.");
var str = Console.ReadLine();
if (String.IsNullOrEmpty(str))
return;
new Thread(() => TestMethod(null, str, "")).Start();
// Allow TestMethod to execute.
Thread.Sleep(100);
unsafe {
// Grab pointer to our string.
var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned);
var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer();
// Change it, one character at a time, wait a little more than
// TestMethod for dramatic effect.
for (int i = 0; i < str.Length; ++i) {
strPtr[i] = 'x';
Thread.Sleep(1100);
}
}
// Tell TestMethod to quit.
_done = true;
Console.WriteLine("Done.");
Console.ReadLine();
}
private static Boolean _done;
public static void TestMethod(String x, String y, String z) {
x = y + z;
while (!_done) {
Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), x);
Thread.Sleep(1000);
}
}
}
Requirements (afaik)
Unsafe context to use pointers.
Use String.Concat(String str0, String str1) which is optimized for cases where str0 == String.Empty or str1 == String.Empty, which returns the non-empty string. Concatenating three or more strings would create a new string which blocks this.
Here's a fixed version of your modified one.
public static class ConsoleApp {
private static Int32 _counter = 10;
public static void Main() {
for (var i = 0; i < 10; i++) {
var str = GetString();
Console.WriteLine("Input: {0} - {1}", DateTime.Now.ToLongTimeString(), str);
new Thread(() => TestMethod(str)).Start();
unsafe {
var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned);
var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer();
strPtr[0] = 'A';
strPtr[1] = 'B';
strPtr[2] = 'C';
strPtr[3] = 'D';
strPtr[4] = 'E';
}
}
Console.WriteLine("Done.");
Console.ReadLine();
}
private static String GetString() {
var builder = new StringBuilder();
for (var i = _counter; i < _counter + 10; i++)
builder.Append(i.ToString());
_counter = _counter + 10;
return builder.ToString();
}
public static void TestMethod(Object y) {
Thread.Sleep(2000);
Console.WriteLine("Output: {0} {1}", DateTime.Now.ToLongTimeString(), y);
}
}
This still works because Object.ToString() is overriden in String to return this, thus returning the exact same reference.

Thanks Simon, here is the my evaluation on this.
In the following code, i spawn threads simply using Thread.Start and the output becomes inconsistent.
This is proving that string passed on to a method can be modified.
If otherwise please explain!
public static class ConsoleApp{
[ThreadStatic]
private static int counter = 10;
public static void Main()
{
string str;
object obj = new object();
// Change it, one character at a time, wait a little more than
// TestMethod for dramatic effect.
for (int i = 0; i < 10; i++)
{
lock (obj)
{
str = GetString();
Console.WriteLine(DateTime.Now.ToLongTimeString());
//ThreadPool.QueueUserWorkItem(TestMethod, str);
new Thread(() => TestMethod(str)).Start();
}
}
Console.WriteLine("Done.");
Console.ReadLine();
}
private static string GetString()
{
object obj = new object();
lock (obj)
{
StringBuilder sb = new StringBuilder();
int temp = 0;
for (int i = counter; i < counter + 10; i++)
{
sb.Append(i.ToString());
temp = i;
}
counter = temp;
return sb.ToString();
}
}
public static void TestMethod(object y)
{
Thread.Sleep(2000);
Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), y.ToString());
}
}
Thanks.

Related

How to save objects in a proper way with the stream writer?

In the program.cs the user is asked if he wanna read the data, if he types y then the method Doc.ReadDoc starts is there any proper way:
class Program
{
static void Main(string[] args)
{
do
{
var path = "C:\\Users\\ks\\Desktop\\C#";
string fileName = path + #"\TestFile.txt";
Console.WriteLine("Do you want to read it? y/n");
string yesorno = Console.ReadLine();
if (yesorno=="y")
{
Console.Clear();
Doc.ReadDoc();
}
Console.WriteLine("Which type of vehicle");
string type = Console.ReadLine();
Console.WriteLine("how many tires");
int raeder = Convert.ToInt32( Console.ReadLine());
var Vehicle = new Used_Cars(type, raeder);
Doc.Write(Vehicle);
} while (true);
}
}
The Class with the methods (Read, Write):
public static List<string> ReadDoc()
{
var list = new List<string>();
var pfad = "C:\\Users\\ks\\Desktop\\C#";
string fileName = path+ #"\TestFile.txt";
try
{
using (StreamReader sr = new StreamReader(fileName))
{
Console.WriteLine("Data found");
string line;
Console.WriteLine(sr.ReadToEnd());
}
}
catch (Exception e)
{
// Let the user know what went wrong.
Console.WriteLine("Data not found");
Console.WriteLine(e.Message);
list = null;
}
return list;
}
And the last Method is the Write method, is this a good code to save properties in a file? How could i stop the program with ESC or smth like that, so if the user presses ESC it should stop.
public static void Write(Used_Cars vehicle)
{
var pfad = "C:\\Users\\ks\\Desktop\\C#";
string fileName = path+ #"\TestFile.txt";
Console.WriteLine("Is it correct?");
Console.WriteLine("y/n");
string yeahorno= Console.ReadLine();
if (jaodernein == "y")
{
try
{
using (StreamWriter writer = new StreamWriter(fileName))
{
writer.WriteLine(vehicle.Vehicle);
writer.WriteLine(vehicle.Wheels);
Console.WriteLine();
}
}
catch (Exception exp)
{
Console.Write(exp.Message);
}
}
}

Spring Batch OOM error

I am using Spring Batch framework for reading the huge file using Partitioner framework. The sample code is attached.
If the file records are going more than 1000 then I am getting Outofmemory error due to ConcurrentHashMap handling in execution context.
public Map<String, ExecutionContext> partition(int gridSize) {
System.out.println("inside Partition" +inboundDir);
// Map<String, ExecutionContext> partitionMap = new HashMap<String, ExecutionContext>();
File file = new File(inboundDir);
System.out.println("is directory"+file.isDirectory());
Map<String, ExecutionContext> queue = new HashMap<>();
try {
List<List<String>> trunks = new ArrayList<>();
System.out.println("Inside File"+file);
// read and store data to a list of trunk
int chunkSize = 1;
int count = 1;
int totalCount=0;
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
List items = new ArrayList();
System.out.println("chunkSize"+chunkSize);
System.out.println("count"+count);
while ((line = br.readLine()) != null) {
totalCount=totalCount+1;
System.out.println("line---------"+count % chunkSize);
if (count % chunkSize == 0) {
trunks.add(items);
items = new ArrayList();
System.out.println("trunks---------"+trunks.size());
}
System.out.println("items---------"+line);
items.add(line);
count++;
System.out.println("count---------"+count);
}
if(items.size()>0){
trunks.add(items);
}
System.out.println("inside total count"+totalCount);
for (int i=2; i<trunks.size(); i++) {
ExecutionContext value = new ExecutionContext();
value.put("fileResource", trunks.get(i));
value.put("totalCount", totalCount);
queue.put("trunk"+i+file, value);
}
}catch(FileNotFoundException e1){
e1.printStackTrace();
}
}
catch (Exception e) {
e.printStackTrace();
}
return queue;
}

NumberFormatException when using FileReader and StringTokenizer

The issue I am having is with the "Office" String. I get this: java.lang.NumberFormatException: For input string: "Office:" I feel like I need to do something else with the parseline down in the tokenizer section? Am I on the right track? I am basically trying to read from a file than I will calculate total sales and write to another file. This is the error I get even when I try to display my people.txt file to an output screen on my GUI. I just need a little advice to where to look to fix this. I have looked up many things but have not came close.
public class PersonReader {
public static void main(String args[]) throws IOException {
PersonReader reader = new PersonReader();
List<person> people = reader.readPeople("people.txt");
System.out.println(people);
}
public List<person> readPeople(String filename) throws IOException {
File f = new File(filename);
FileReader reader = new FileReader(f);
BufferedReader breader = new BufferedReader(reader);
List<person> people = new ArrayList<person>();
String line = breader.readLine();
while (line != null) {
person p = null;
try {
p = parseLine(line);
} catch (Exception e) {
e.printStackTrace();
}
if (p == null) {
System.out.println("This row is bad." + line);
} else {
people.add(p);
}
line = breader.readLine();
}
return people;
}
private static person parseLine(String line) {
int repID;
String firstName;
String lastName;
double books;
double paper;
double office;
String district;
String contact;
String next;
StringTokenizer st = new StringTokenizer(line, ", ");
repID = Integer.parseInt(st.nextToken().trim());
firstName = st.nextToken().trim();
lastName = st.nextToken().trim();
books = Double.parseDouble(st.nextToken().trim());
parseLine(line);
paper = Double.parseDouble(st.nextToken().trim());
parseLine(line);
office = Double.parseDouble(st.nextToken().trim());
parseLine(line);
district = st.nextToken().trim();
parseLine(line);
contact = st.nextToken().trim();
parseLine(line);
if (repID < 1) {
return null;
}
if (firstName.length() == 0) {
return null;
}
if (lastName.length() == 0) {
return null;
}
if (books < 1) {
return null;
}
if (paper < 1) {
return null;
}
if (office < 1) {
return null;
}
if (district.length() == 0) {
return null;
}
if (contact.length() == 0) {
return null;
}
person p = new person();
p.setRepID(repID);
p.setFirstName(firstName);
p.setLastName(lastName);
p.setBooks(books);
p.setPaper(paper);
p.setOffice(office);
p.setDistrict(district);
p.setContact(contact);
return p;
}
}

SignalR. Timer is not stopping on the server

We are using SignalR for information exchange.
When the web browser is connected a timer starts, but it is not stopping when user close the browser.
Here is the code. starttimer function runs when browser connected.
When user disconnect the browser, timer still running on the server.
[HubName("myChatHub")]
public class InboundCallsDataShare : Hub
{
private OverrideTimer timer ;
private List<GroupNConnectionId> groupsList = new List<GroupNConnectionId>();
public void send(string message)
{
Clients.All.addMessage(message);
//Clients..addMessage(message);
}
public void starttimer(string queue)
{
//var connectionId = this.Context.ConnectionId;
//GroupNConnectionId objGroupNConnectionId=new GroupNConnectionId();
//objGroupNConnectionId.Group = queue;
//objGroupNConnectionId.ConnectionID = connectionId;
//if(groupsList.Contains(objGroupNConnectionId))return;
//////////////////////////////////////////////////////
//groupsList.Add(objGroupNConnectionId);
Groups.Add(this.Context.ConnectionId, queue);
timer = new OverrideTimer(queue);
timer.Interval = 15000;
timer.Elapsed +=new EventHandler<BtElapsedEventArgs>(timer_Elapsed);
//first time call
timer_Elapsed(timer,new BtElapsedEventArgs(){Queue = queue});
//ends
timer.Start();
Console.WriteLine("Timer for queue " +queue);
}
public override Task OnConnected()
{
return base.OnConnected();
}
public override Task OnDisconnected()
{
//timer.Stop();
return base.OnDisconnected();
}
public void getdatafromxml(string queue)
{
string list = (new Random()).Next(1, 10000).ToString();
Clients.All.getList(list);
//Clients..addMessage(message);
}
public ICBMObject GetInterationList(string queue)
{
//ININInterations.QueueListViewItemData _obj = new ININInterations.QueueListViewItemData();
return GetInboundCallCountFromXML(queue);
//return _obj.MainFunctionIB();
}
void timer_Elapsed(object sender, BtElapsedEventArgs e)
{
ICBMObject objICBMObject = GetInboundCallCountFromXML(e.Queue);
Clients.Group(e.Queue).getList(objICBMObject);
CreateFile(e.Queue);
//Clients.All.getList(objICBMObject);
}
private void CreateFile(string queue)
{
string path = #"D:\t.txt";
string text = File.ReadAllText(path);
text += queue+ DateTime.Now.ToString() + Environment.NewLine;
File.WriteAllText(path, text);
}
public ICBMObject GetInboundCallCountFromXML(string queue)
{
FileStream fs = null;
int totalInboundCalls = 0,
totalInboundCallsUnassigned = 0;
string longestDuration = "";
bool updateText = false;
try
{
XmlDataDocument xmldoc = new XmlDataDocument();
XmlNodeList xmlnode;
int i = 0;
string str = null;
fs = new FileStream(AppDomain.CurrentDomain.BaseDirectory + "InboundXML/" + queue + ".xml",
FileMode.Open, FileAccess.Read);
if (fs.CanRead)
{
xmldoc.Load(fs);
xmlnode = xmldoc.GetElementsByTagName(queue);
for (i = 0; i <= xmlnode.Count - 1; i++)
{
totalInboundCalls = Convert.ToInt32(xmlnode[i].ChildNodes.Item(0).InnerText.Trim());
totalInboundCallsUnassigned = Convert.ToInt32(xmlnode[i].ChildNodes.Item(1).InnerText.Trim());
longestDuration = xmlnode[i].ChildNodes.Item(2).InnerText.Trim();
}
updateText = true;
}
}
catch (Exception)
{
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
return new ICBMObject()
{
TotalInboundCalls = totalInboundCalls,
TotalInboundCallsUnassigned = totalInboundCallsUnassigned,
LongestDuration = longestDuration,
UpdateText = updateText
//string.Format("{0:D2}:{1:D2}:{2:D2}",
// _LongetInbound.Hours,
// _LongetInbound.Minutes,
// _LongetInbound.Seconds)
};
}
}
Besides the fact that its commented out? Did you put a break point on the timer to see if its getting hit at all? It might be that there is a delay in calling the onDisconnect, if the timeout property is set too large, it might not fire. it might be entering onReconnected if it does not know the client is closed.

How to cache global information for all users?

I have my first bigger asp.net website and there are userlists of all user online - of course this list is the same for every user, but as a normal online list I update this with PageMethod / WebMethod every 10 seconds.
So if 100 users online that means 10x6x100 = 6000 database querys each minute.
How can I avoid that?
Can I save this information for all user in something like a session / querystring / cookie but global for all users to avoid querys?
The Simplest way is to create an Application Variable or DataTable, which will hold your Required Information.
After each 10 minutes, when you update the records, Just update the Application Datatable you created above. This DataTable is common for all the users and that will decrease your load drastically.
Let me know if you need code.
You may us static variable for this. If you are having more than 1 app-pool to serverpages
then use asp.net caching since static variable are not thread safe.
Here is my code that i use for something similar it has 2 class.
class1
using System;
public class onlineuser
{
public string sessionid = "";
public string username = "";
public string currentpage = "";
public DateTime time = DateTime.Now;
public onlineuser()
{
//
// TODO: Add constructor logic here
//
}
}
class2
using System;
using System.Collections;
using System.Data;
public class user
{
public static ArrayList online;
public static void adduser(string sessionid,string username,string currentpage)
{
removeunused();
remove(sessionid);
onlineuser ou = new onlineuser();
ou.sessionid = sessionid;
ou.username = username;
ou.currentpage = currentpage;
ou.time = DateTime.Now;
if (online==null)
{
online = new ArrayList();
}
online.Add(ou);
online.TrimToSize();
}
public static void remove(string sessionid)
{
if (online==null)
{
return;
}
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
if (ou.sessionid == sessionid)
{
online.RemoveAt(i);
online.TrimToSize();
return;
}
}
}
public static void removeunused()
{
if (online == null)
{
return;
}
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
if (ou.time < DateTime.Now.AddMinutes(-2))
{
online.RemoveAt(i);
online.TrimToSize();
return;
}
}
}
public static DataTable totable()
{
DataTable dt = new DataTable();
DataColumn dc = new DataColumn("SessionId", typeof(string));
DataColumn dc1 = new DataColumn("UserName", typeof(string));
DataColumn dc2 = new DataColumn("currentpage", typeof(string));
DataColumn dc3 = new DataColumn("Time", typeof(DateTime));
dt.Columns.Add(dc);
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
dt.Columns.Add(dc3);
if (online!=null)
{
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
dt.Rows.Add(new object[] {ou.sessionid,ou.username,ou.currentpage,ou.time});
}
}
return dt;
}
}
following code is placed in mymaster page which update userlist
try
{
string uname= "N/A";
if (Session["uname"]!=null)
{
uname = Session["uname"].ToString();
}
string page = Path.GetFileName(Request.PhysicalPath).Trim().ToLower();
if (Request.QueryString!=null)
{
page += "?"+Request.QueryString.ToString();
}
user.adduser(Session.SessionID, uname, page);
}
catch (Exception)
{
}

Resources