I am developing in C# two simple applications, running in the same local machine without network requirements.
The first application initializes an DLL (Class1) and set a variable. The second application just read it the data which was previously stored. Both applications instanciates the same Class1.
Code:
DLL (Class1):
public class Class1
{
private string variableName;
public string MyProperty
{
get { return variableName; }
set { variableName = value; }
}
}
Application A:
class Program
{
static void Main(string[] args)
{
Class1 class1 = new Class1();
string localReadVariable = Console.ReadLine();
class1.MyProperty = localReadVariable;
}
}
Application B:
class Program
{
static void Main(string[] args)
{
ClassLibraryA.Class1 localClass = new ClassLibraryA.Class1();
string z = localClass.MyProperty;
Console.WriteLine(z);
}
}
My problem is that I do not know how to read a variable from another thread.
Application B must read the "variableName" set by application B
Thank you
You need some sort of mechanism to communicate between the applications.
This can be through the registry, files, memory mapped files etc...
If both applications are expected to do write, you need to add synchronization logic to your code.
There is no simple way for Application B to read data created in Application A. Each application has its own address space and thus do not know of the others existence.
But, there are ways to do this!
See this question for one method..
I've successfully used two methods:
Use a database table to contain your common data. If you wrap your
calls to it in transactions then you also protection from
concurrency issues.
Use PersistentDictionary to store your data, protected by a mutex. You must have some interprocess locking since PersistentDictionary can only be open by one process at a time.
You can use .net Remoting to communicate between your two application.
Remoting also does not require a network address to communicate.
Related
I created a static ip and log class.
the ip class find out the users ip address and log class log it into a text file.
every thing work just fine but i wonder what happens if so many requests came at a same time?
i mean the both classes are static and base on static classes it causes problem.
how can i managed them?
here is my ip class:
public static class IP
{
public static string IP()
{
System.Web.HttpContext context = System.Web.HttpContext.Current;
string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (!string.IsNullOrEmpty(ipAddress))
{
string[] addresses = ipAddress.Split(',');
if (addresses.Length != 0)
{
return addresses[0];
}
}
return context.Request.ServerVariables["REMOTE_ADDR"];
}
}
}
and here part of my log class which write into the text file:
private static void WriteLine(string message)
{
string filePath = FilePath();
CreateFile(filePath);
try
{
using (StreamWriter log = File.AppendText(filePath))
log.WriteLine(message);
}
catch (Exception)
{
//If can not access to file do nothing
//throw;
}
}
You aren't going to run into contention problems due to your classes being static. Your IP.IP() method class is pure (i.e. it does not change the state of anything) and contains no locks, so there is no chance of there being any contention there.
You do potentially have problems in WriteLine due to the fact that you are probably writing your log file on the same thread as you are doing your work. That means the file write is acting as a lock since only one write can occur at any one time.
What you want is to log to a queue and then to write that queue on a separate thread; that is a classic producer-consumer pattern.
Alternatively you could avoid reinventing the wheel and use an existing logging framework that will handle these things for you like log4net
Streamwriter has a default of 4kb buffer which can be modified if needed as defined by:
public StreamWriter(
Stream stream,
Encoding encoding,
int bufferSize
)
More than likely, your computer (including disk access) is most likely a lot faster than your internet access.
It will work fine, because you don't have any public variable which will be kept in memory and changing on every time class is accessed.
So as the method ends, the scope of your variables will be finished.
However if they are in memory, they will not be effected by how many users use it at the same time, and there will be no mess.
I post this specific question after the other one I wasn't able to solve.
Briefly: even if I create a static class (with static vars and/or properties), main app and background agent don't use the same static class, but both create a new instance of it; so it's impossible to share data between these projects!!
To test it:
Create a new Windows Phone application (called AppTest)
Add a ScheduledTask project (called Agent)
In AppTest put a reference to project Agent
Create a new Windows Phone Library project (called Shared)
Both in AppTest and Agent put a reference to project Shared
Then use this basic test code.
AppTest
private readonly string taskName = "mytest";
PeriodicTask periodicTask = null;
public MainPage()
{
InitializeComponent();
Vars.Apps.Add("pluto");
Vars.Order = 5;
StartAgent();
}
private void RemoveTask()
{
try
{
ScheduledActionService.Remove(taskName);
}
catch (Exception)
{
}
}
private void StartAgent()
{
periodicTask = ScheduledActionService.Find(taskName) as PeriodicTask;
if (periodicTask != null)
RemoveTask();
periodicTask = new PeriodicTask(taskName)
{
Description = "test",
ExpirationTime = DateTime.Now.AddDays(14)
};
try
{
ScheduledActionService.Add(periodicTask);
ScheduledActionService.LaunchForTest(taskName,
TimeSpan.FromSeconds(10));
}
catch (InvalidOperationException exception)
{
}
catch (SchedulerServiceException)
{
}
}
Agent
protected override void OnInvoke(ScheduledTask task)
{
if (Vars.Apps.Count > 0)
Vars.Order = 1;
NotifyComplete();
}
Shared
public static class Vars
{
public static List<string> Apps = null;
public static int Order;
static Vars()
{
Apps = new List<string>();
Order = -1;
}
}
When you debug main app you can see that static constructor for static class is invoked (this is correct), but when agent is invoked Vars is not "used" but constructor is invoked another time, so creating a different instance.
Why? How can I share data between main app and background agent?
I've already tried to put Vars class in agent class and namespace, but the behaviour is the same.
Easiest thing is to use Isolated storage. For example, from the main app:
using (Mutex mutex = new Mutex(true, "MyData"))
{
mutex.WaitOne();
try
{
IsolatedStorageSettings.ApplicationSettings["order"] = 5;
}
finally
{
mutex.ReleaseMutex();
}
}
//...
and in the agent:
using (Mutex mutex = new Mutex(true, "MyData"))
{
mutex.WaitOne();
try
{
order = (int)IsolatedStorageSettings.ApplicationSettings["order"];
}
finally
{
mutex.ReleaseMutex();
}
}
// do something with "order" here...
You need to use Process-level synchronization and Mutex to guard against data corruption because the agent and the app are two separate processes and could be doing something with isolated storage at the same time.
Values of static variables are 'instanced' per loaded App Domain, which is a 'subset' of your running process. So static variables have different values per AppDomain, and therefore also per running process.
If you have to share data between processes, you need either to store it somewhere (e.g. a database), or you need to setup some communication between the processes (e.g. MSMQ or WCF).
Hope this helps.
After a long search, I finally found an article stating:
Since our EvenTiles application and its PeriodicTask are running in
separate processes, they are completely separated from each other,
meaning that they get their own copies of variables they both want to
access, even though these variables are defined in a separate project.
So it's impossible to share data between main app and periodic task using "simple" static variables/properties; we must read/write a database or the isolated storage or whatever we please.
I find this crazy, but this is the story.
MS recommends the following:
Communication Between Foreground Application and Background Agent
Passing information between the foreground application and background agents can be challenging because it is not possible to predict if the agent and the application will run simultaneously. The following are recommended patterns for this.
1.For Periodic and Resource-intensive Agents: Use LINQ 2 SQL or a file in isolated storage that is guarded with a Mutex. For one-direction communication where the foreground application writes and the agent only reads, we recommend using an isolated storage file with a Mutex. We recommend that you do not use IsolatedStorageSettings to communicate between processes because it is possible for the data to become corrupt.
2.For Audio Agents: Store custom data in the Tag property of the AudioTrack class. For notifications from the audio agent to the foreground application, read the Tag property in the PlayStateChanged event handler. To pass data from the foreground application to the audio agent, read the Tag property of the current track in the implementation of the OnPlayStateChanged(BackgroundAudioPlayer, AudioTrack, PlayState) method.
See here: http://msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx
I know that a static variable used in a web application is shared for all users across the web application. If I have a library (DLL) that uses some static private variable, do all applications using that library share the value of that variable?
For example, say I have the following code in my DLL:
private static bool isConnected = false;
public static void Connect()
{
// TODO: Connect.
isConnected = true;
}
public static void Disconnect()
{
// TODO: Disconnect.
isConnected = false;
}
Then in Application A, I call myDLL.Connect() which sets the value of isConnected to True. Then I have some Application B that does the same thing. If Application A later calls myDLL.Disconnect(), does Application B see isConnected as False because the two applications share the same DLL file with a static variable? The DLL file would, in this case, be literally the same file in the same file path.
(I previously asked a somewhat similar question about web applications here. It is not related.)
No they won't. They are loaded in separate AppDomains and cannot see each other's instances.
Even if they refer to same physical file, each application gets its own private instance of the assembly.
I have to restrict my .net 4 WPF application so that it can be run only once per machine. Note that I said per machine, not per session.
I implemented single instance applications using a simple mutex until now, but unfortunately such a mutex is per session.
Is there a way to create a machine wide mutex or is there any other solution to implement a single instance per machine application?
I would do this with a global Mutex object that must be kept for the life of your application.
MutexSecurity oMutexSecurity;
//Set the security object
oMutexSecurity = new MutexSecurity();
oMutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), MutexRights.FullControl, AccessControlType.Allow));
//Create the global mutex and set its security
moGlobalMutex = new Mutex(True, "Global\\{5076d41c-a40a-4f4d-9eed-bf274a5bedcb}", bFirstInstance);
moGlobalMutex.SetAccessControl(oMutexSecurity);
Where bFirstInstance returns if this is the first instance of your application running globally. If you omited the Global part of the mutex or replaced it with Local then the mutex would only be per session (this is proberbly how your current code is working).
I believe that I got this technique first from Jon Skeet.
The MSDN topic on the Mutex object explains about the two scopes for a Mutex object and highlights why this is important when using terminal services (see second to last note).
I think what you need to do is use a system sempahore to track the instances of your application.
If you create a Semaphore object using a constructor that accepts a name, it is associated with an operating-system semaphore of that name.
Named system semaphores are visible throughout the operating system, and can be used to synchronize the activities of processes.
EDIT: Note that I am not aware if this approach works across multiple windows sessions on a machine. I think it should as its an OS level construct but I cant say for sure as i havent tested it that way.
EDIT 2: I did not know this but after reading Stevo2000's answer, i did some looking up as well and I think that the "Global\" prefixing to make the the object applicable to the global namespace would apply to semaphores as well and semaphore, if created this way, should work.
You could open a file with exclusive rights somewhere in %PROGRAMDATA%
The second instance that starts will try to open the same file and fail if it's already open.
How about using the registry?
You can create a registry entry under HKEY_LOCAL_MACHINE.
Let the value be the flag if the application is started or not.
Encrypt the key using some standard symmetric key encryption method so that no one else can tamper with the value.
On application start-up check for the key and abort\continue accordingly.
Do not forget to obfuscate your assembly, which does this encryption\decryption part, so that no one can hack the key in registry by looking at the code in reflector.
I did something similar once.
When staring up the application list, I checked all running processes for a process with identical name, and if it existed I would not allow to start the program.
This is not bulletproof of course, since if another application have the exact same process name, your application will never start, but if you use a non-generic name it will probably be more than good enough.
For the sake of completeness, I'd like to add the following which I just found now:
This web site has an interesting approach in sending Win32 messages to other processes. This would fix the problem of the user renaming the assembly to bypass the test and of other assemblies with the same name.
They're using the message to activate the main window of the other process, but it seems like the message could be a dummy message only used to see whether the other process is responding to it to know whether it is our process or not.
Note that I haven't tested it yet.
See below for full example of how a single instace app is done in WPF 3.5
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances.
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}
Second part:
public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
WpfApp.current = this;
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
doc.LoadFile(filename);
doc.Owner = this.MainWindow;
doc.Show();
// If the application is already loaded, it may not be visible.
// This attempts to give focus to the new window.
doc.Activate();
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}
Third part:
public class Startup
{
[STAThread]
public static void Main(string[] args)
{
SingleInstanceApplicationWrapper wrapper =
new SingleInstanceApplicationWrapper();
wrapper.Run(args);
}
}
You may need to add soem references and add some using statements but it shoudl work.
You can also download a VS example complete solution by downloading the source code of the book from here.
Taken From "Pro WPF in C#3 2008 , Apress , Matthew MacDonald" , buy the book is gold. I did.
I am creating a custom .net hardware framework that will be used by other programmers to control some hardware. They will add a reference to our DLL to get to our hardware framework. I am in need of a shared class that will be accessed from multiple applications (processes).
The singleton pattern seems to be what I need but it only works for multiple threads inside your process. I could be completely wrong but here is an example of the C# code I currently have. I can't help to feel that the design is incorrect. I wish I could share more specific information but I can't.
I must stress that I will have no control over the customer application. The solution must be contained inside the framework (DLL) itself.
The Framework: (Shared DLL)
public class Resources
{
static readonly Resources m_instance = new Resources();
public string Data;
private Resources()
{
Data = DateTime.Now.ToString();
}
public static Resources Instance
{
get
{
return m_instance;
}
}
}
The Test Application: (eventually customer app)
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press enter to capture the resource!");
Console.ReadLine();
var resources = Resources.Instance;
Console.WriteLine("\r\n{0}: {1}\r\n", Thread.CurrentThread.ManagedThreadId, resources.Data);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += WorkerDoWork;
worker.RunWorkerAsync();
while (worker.IsBusy)
{
Thread.Sleep(100);
}
Console.WriteLine("Press enter to close the process!");
Console.ReadLine();
}
static void WorkerDoWork(object sender, DoWorkEventArgs e)
{
var resources = Resources.Instance;
Console.WriteLine("\r\n{0}: {1}\r\n", Thread.CurrentThread.ManagedThreadId, resources.Data);
}
}
The first launched application gives an output of:
Press enter to capture the resource!
1: 6/24/2009 8:27:34 AM
3: 6/24/2009 8:27:34 AM
Press enter to close the process!
The second application gives an output of:
Press enter to capture the resource!
9: 6/24/2009 8:27:35 AM
10: 6/24/2009 8:27:35 AM
Press enter to close the process!
Conclusion:
I would like to see both applications return the same string of the time of the first instantiation of the class.
As you can see the singleton works for the multiple thread inside the process but not cross processes. Maybe this can't be done for I can't seem to find any solution.
Yes it is possible to share a singleton amongst several processes. However you will need to take advantage of a technology which supports interprocess communication in order to achieve this result.
The most popular technologies which allow you to share out your object fairly directly are Remoting and WCF.
Giving an example of sharing a singleton with either of these is beyond the scope of an SO answer. But there are many tutorials on the web for each of these. Googling either technology plus singleton should put you on the right path.
You cannot use a singleton to sync across applications. Each runs in its own application space, and as a matter of security cannot access memory/objects/etc. from the other without a method of communication (like remoting) To sync the two they would have to remote into a third program.
To add to the Kevin's answer, your constructor for your class Resources should really be made private for it to be a true singleton, otherwise nothing is stopping someone from creating a new instance of the Resources class through the constructor. This doesn't solve your problem, but it does stop one from misusing the Singleton.
Simply calling a singleton property in a different assembly from two different processes will create different instances of that class.
But you can easily share information between processes using .Net Remoting, or fire interprocess events if you only need simple signaling (EventWaitHandle).
[Edit:] To make it look like a Singleton to your callers, you can expose a class which will internally use Remoting to instantiate a singleton, and then return the instance transparently. Here is an example which (I think) does that: http://www.codeproject.com/KB/dotnet/remotingsingleton.aspx
There are ways to do it as mentioned above. But it is clumsy if you use WCF or remoting. Please try interprocess thread sync techniques.
For more info read the online free e-book on threading
http://www.albahari.com/threading/
Specially see the cross process sync constructs here ...
http://www.albahari.com/threading/part2.aspx#_Synchronization_Essentials