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.
Related
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);
}
}
}
I am developing a Windows phone 8 app that needs to upload photos to amazon s3 storage. However, I find that this is impossible since the HttpClient time out after about 60 seconds regardless of what timeout setting I use.
Is there really no way to upload large files from Windows Phone?
BackgroundTransferRequest is useless since it cannot send the neccessary metadata with file uploads.
I use this code (which times out):
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMinutes(30);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, m_uploadUrl);
httpContent.Headers.Add("Keep-Alive", "true");
request.Content = httpContent; // 3-5 Mb file
response = await httpClient.SendAsync(request);
statusCode = response.StatusCode;
}
I also tried PostAsync(), but same result. After about 60 sec the call completes with a status code 400 or 404. This is not a server timeout. IPhone and Android apps use the same service. No problems there.
Any ideas on how to upload files that takes more than 60 seconds to send?
I too faced similar things. The timeout glitch.
Check if you could use another class instead of HttpClient.
WebClient may be.
Check if this helps you:
http://blog.anthonybaker.me/2013/06/how-to-upload-file-from-windows-phone.html
and even this:
http://chriskoenig.net/2011/08/19/upload-files-from-windows-phone/
I got things working for me with those.
I've used several days now to implement a new uploader and get all the details working. I used HttpWebRequest with the async methods and split the file into chuncks. Finally I got it working and it uploads without the timeout. Here is the complete code:
using System;
using Models;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Services
{
public class UploadData
{
public Stream PostStream { get; set; }
public Stream FileStream { get; set; }
public byte[] HeaderBytes {get; set;}
public byte[] FooterBytes {get; set;}
public byte[] Buffer { get; set; }
public Photo Upload { get; set; }
public int BytesWritten { get; set; }
}
public class UploadEventArgs : EventArgs
{
public Photo Upload { get; set; }
public int Progress { get; set; }
}
public class UploadService
{
public delegate void CompletedEventHandler(object sender, UploadEventArgs e);
public event CompletedEventHandler UploadCompleted;
public delegate void ProgressEventHandler(object sender, UploadEventArgs e);
public event ProgressEventHandler ProgressChanged;
private static string contentType = "multipart/form-data; boundary={0}";
private static string headerString = "Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"\r\nContent-Type: Content-Type: application/octet-stream\r\n\r\n";
private HttpWebRequest m_request;
private static string boundarystr;
private UploadData m_uploadData;
private bool m_isStopped;
public async Task StartUpload(Photo upload, Uri uri, Dictionary<string, string> parameters)
{
try
{
m_isStopped = false;
var fileStream = (await upload.File.OpenReadAsync()).AsStreamForRead();
var uploadData = new UploadData();
boundarystr = "---------------------------" + DateTime.Now.Ticks.ToString("x");
string para = GetParamsString(parameters);
string headAndParams = para + String.Format(headerString, HttpUtility.UrlEncode(upload.File.Name));
var headerBytes = System.Text.Encoding.UTF8.GetBytes(headAndParams);
var footerBytes = Encoding.UTF8.GetBytes("\r\n--" + boundarystr + "--\r\n");
uploadData.Upload = upload;
uploadData.FileStream = fileStream;
uploadData.FooterBytes = footerBytes;
uploadData.HeaderBytes = headerBytes;
uploadData.BytesWritten = 0;
m_uploadData = uploadData;
m_request = (HttpWebRequest)WebRequest.Create(uri);
m_request.Method = "POST";
m_request.AllowWriteStreamBuffering = false;
m_request.ContentType = string.Format(contentType, boundarystr);
m_request.ContentLength = fileStream.Length + headerBytes.Length + footerBytes.Length;
var asyncResult = m_request.BeginGetRequestStream((ar) => { GetRequestStreamCallback(ar, uploadData); }, m_request);
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Start upload failed: " + ex.Message);
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
m_uploadData.FileStream.Close();
m_uploadData.PostStream.Close();
OnUploadComplete(argsStopped);
}
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult, UploadData uploadData)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
postStream.Write(uploadData.HeaderBytes, 0, uploadData.HeaderBytes.Length);
var args = new UploadEventArgs();
args.Upload = uploadData.Upload;
args.Progress = 1;
OnProgressChanged(args);
uploadData.PostStream = postStream;
WriteNextChunck(uploadData);
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Header write failed: " + ex.Message);
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
m_uploadData.FileStream.Close();
m_uploadData.PostStream.Close();
OnUploadComplete(argsStopped);
}
}
private void WriteNextChunck(UploadData upload)
{
try
{
if ((upload.FileStream.Length - upload.BytesWritten) >= 16 * 1024)
{
upload.Buffer = new byte[16 * 1024];
}
else
{
// Last part
upload.Buffer = new byte[upload.FileStream.Length - upload.BytesWritten];
}
upload.FileStream.Read(upload.Buffer, 0, (int)upload.Buffer.Length);
upload.PostStream.BeginWrite(upload.Buffer, 0, upload.Buffer.Length, BeginWriteCallback, upload);
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Buffer write failed: " + ex.Message);
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
upload.FileStream.Close();
upload.PostStream.Close();
OnUploadComplete(argsStopped);
}
}
private void BeginWriteCallback(IAsyncResult ar)
{
try
{
var upload = ar.AsyncState as UploadData;
upload.PostStream.EndWrite(ar);
upload.BytesWritten += upload.Buffer.Length;
var args = new UploadEventArgs();
args.Upload = upload.Upload;
args.Progress = (int)(((decimal)upload.BytesWritten / (decimal)upload.FileStream.Length) * 100);
OnProgressChanged(args);
if (m_isStopped)
{
upload.FileStream.Close();
upload.PostStream.Close();
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Upload stopped");
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
OnUploadComplete(argsStopped);
return;
}
// write next chunck
if (upload.BytesWritten < upload.FileStream.Length)
{
WriteNextChunck(upload);
}
if (upload.BytesWritten >= upload.FileStream.Length)
{
WriteFooter(upload);
}
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Upload write failed: " + ex.Message);
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
OnUploadComplete(argsStopped);
}
}
private void WriteFooter(UploadData upload)
{
try
{
upload.PostStream.Write(upload.FooterBytes, 0, upload.FooterBytes.Length);
upload.PostStream.Close();
var asyncResult = m_request.BeginGetResponse(new AsyncCallback(GetResponseCallback), m_request);
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = new Exception("Footer write failed: " + ex.Message);
var argsStopped = new UploadEventArgs();
argsStopped.Upload = m_uploadData.Upload;
OnUploadComplete(argsStopped);
}
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
streamResponse.Close();
streamRead.Close();
response.Close();
m_uploadData.FileStream.Close();
m_uploadData.Upload.UploadInfo.StatusCode = response.StatusCode;
if (response.StatusCode == HttpStatusCode.NoContent)
{
m_uploadData.Upload.UploadInfo.Exception = null;
}
else
{
m_uploadData.Upload.UploadInfo.Exception = new Exception(responseString);
}
var args = new UploadEventArgs();
args.Upload = m_uploadData.Upload;
args.Progress = 100;
OnUploadComplete(args);
}
catch (Exception ex)
{
m_uploadData.Upload.UploadInfo.StatusCode = HttpStatusCode.NotFound;
m_uploadData.Upload.UploadInfo.Exception = ex;
var args = new UploadEventArgs();
args.Upload = m_uploadData.Upload;
OnUploadComplete(args);
}
}
private string GetParamsString(Dictionary<string, string> parameters)
{
bool needsCLRF = false;
string result = "";
foreach (var param in parameters)
{
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
result += "\r\n";
needsCLRF = true;
string prm = string.Format("--{0}\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Disposition: form-data; name={1}\r\n\r\n{2}",
boundarystr,
param.Key,
param.Value);
result += prm;
}
// Add the end of the request. Start with a newline
string footer = "\r\n--" + boundarystr + "\r\n";
result += footer;
return result;
}
protected virtual void OnUploadComplete(UploadEventArgs e)
{
if (UploadCompleted != null)
UploadCompleted(this, e);
}
protected virtual void OnProgressChanged(UploadEventArgs e)
{
if (ProgressChanged != null)
ProgressChanged(this, e);
}
public void Stop()
{
m_isStopped = true;
}
}
}
My server receive some TCP/IP data and response to client:
private static void startClient(TcpClient clientSocket)
{
NetworkStream networkStream = null;
DateTime fecha = DateTime.Now;
try
{
clientSocket.NoDelay = true;
networkStream = clientSocket.GetStream();
string receiveData = readData(clientSocket);
string responseData = "abc"; //ProcessData(receiveData);
if (responseData != null)
writeData(networkStream, responseData);
}
catch (SocketException e)
{
throw;
}
finally
{
networkStream.Close();
}
}
private static string readData(TcpClient tcpClient)
{
try
{
var bytesFrom = new byte[tcpClient.ReceiveBufferSize];
StringBuilder dataFromClient = new StringBuilder();
int readCount;
while ((readCount = tcpClient.GetStream().Read(bytesFrom, 0, tcpClient.ReceiveBufferSize)) != 0)
{
dataFromClient.Append(Encoding.ASCII.GetString(bytesFrom, 0, readCount));
}
//int bytesRead = tcpClient.GetStream().Read(bytesFrom, 0, tcpClient.ReceiveBufferSize);
//string dataFromClient = Encoding.ASCII.GetString(bytesFrom, 0, bytesRead);
return dataFromClient.ToString();
}
catch (SocketException e)
{
throw;
}
}
private static void writeData(NetworkStream networkStream, string dataToClient)
{
Byte[] sendBytes = null;
try {
sendBytes = Encoding.ASCII.GetBytes(dataToClient);
networkStream.Write(sendBytes,0, sendBytes.Length);
networkStream.Flush();
}
catch(SocketException e)
{
throw;
}
}
With this solution the client never receives the response sent:
http://postimg.org/image/6srtslf2f/
However changing the reception to a single call to NetworkStream.Read ...
private static string readData(TcpClient tcpClient)
{
try
{
var bytesFrom = new byte[tcpClient.ReceiveBufferSize];
int bytesRead = tcpClient.GetStream().Read(bytesFrom, 0, tcpClient.ReceiveBufferSize);
string dataFromClient = Encoding.ASCII.GetString(bytesFrom, 0, bytesRead);
return dataFromClient.ToString();
}
catch (SocketException e)
{
throw;
}
}
... the client receives the response
http://postimg.org/image/uih9hadfr/
UPDATE
I found solution here. I´ve fixed it using 2/3 ways described . First handle EOS end message. Seccond is setting receive timeout if client works bad and sends bad data without EOS:
private static string readData(TcpClient tcpClient)
{
var clientStream = tcpClient.GetStream();
var dataFromClient = string.Empty;
var buffer = new byte[RECEIVE_BUFFER_SIZE];
if (!clientStream.CanRead)
return "";
tcpClient.ReceiveTimeout = RECEIVE_TIMEOUT;
try
{
int readCount;
while ((readCount = clientStream.Read(buffer, 0, buffer.Length)) != 0)
{
dataFromClient += Encoding.ASCII.GetString(buffer, 0, readCount);
if (dataFromClient.EndsWith(EOS))
return dataFromClient;
}
return dataFromClient.ToString();
}
catch (Exception ex)
{
var socketExept = ex.InnerException as SocketException;
if (socketExept != null && socketExept.SocketErrorCode == SocketError.TimedOut)
Logger.Warn(string.Format("Se excedio el timeout de recepcion: {0} ms",RECEIVE_TIMEOUT));
else
Logger.Error(string.Format("Error leyendo el mensaje recibido"), ex);
return dataFromClient.ToString();
}
}
I want to force my program to wait some moments after doing something, and then do somwthing else, in asp.net and silverlight.
(In Detail, I want to upload an image by silverlight program, and then show it in my page by an Image control. But when I upload images which their size is about 6KB or upper, the image doesn't show, however it has been uplaoded successfully. I think that waiting some moments may solve the problem)
May anyone guide me?
thank you
I use the code in this page
This is the code in MyPage.Xaml:
private void UploadBtn_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Multiselect = false;
dlg.Filter = UPLOAD_DIALOG_FILTER;
if ((bool)dlg.ShowDialog())
{
progressBar.Visibility = Visibility.Visible;
progressBar.Value = 0;
_fileName = dlg.File.Name;
UploadFile(_fileName, dlg.File.OpenRead());
}
else
{
//user clicked cancel
}
}
private void UploadFile(string fileName, Stream data)
{
// Just kept here
progressBar.Maximum = data.Length;
UriBuilder ub = new UriBuilder("http://mysite.com/receiver.ashx");
ub.Query = string.Format("fileName={0}", fileName);
WebClient c = new WebClient();
c.OpenWriteCompleted += (sender, e) =>
{
PushData(data, e.Result);
e.Result.Close();
data.Close();
};
try
{
c.OpenWriteAsync(ub.Uri);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
private void PushData(Stream input, Stream output)
{
byte[] buffer = new byte[input.Length];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) != 0)
{
output.Write(buffer, 0, buffer.Length);
}
progressBar.Value += input.Length;
if (progressBar.Value >= progressBar.Maximum)
{
progressBar.Visibility = System.Windows.Visibility.Collapsed;
loadImage();
}
}
private void loadImage()
{
Uri ur = new Uri("http://mysite.com/upload/" + _fileName);
img1.Source = new BitmapImage(ur);
}
And this is receiver.ashx:
public void ProcessRequest(HttpContext context)
{
string filename = context.Request.QueryString["filename"].ToString(); using (FileStream fs = File.Create(context.Server.MapPath("~/upload/" + filename)))
{
SaveFile(context.Request.InputStream, fs);
}
}
private void SaveFile(Stream stream, FileStream fs)
{
byte[] buffer = new byte[stream.Length];
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
fs.Write(buffer, 0, bytesRead);
}
}
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.