473,657 Members | 2,484 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

c# multithreading -- really confused!

9 New Member
Hi all,

I have several threads running (basically they are copying files from one place to another). I am using log4net for logging...Howev er, sometimes i get a log4net error due to log file being used by other process. I thought about creating a method which will take care of the logging...all threads will used a delegate to call the method that does the logging

static readonly object lockerLog = new object();
public delegate void UpdateLogDelega te(string txt,string type)

Expand|Select|Wrap|Line Numbers
  1. public void LogInfo(string txt, string type)
  2.         {
  3.             lock (lockerLog)
  4.             {
  5.                 switch (type)
  6.                 {
  7.                     case "ERROR":
  8.                     Logging.log.Error(txt);
  9.                     break;
  10.  
  11.                     case "DEBUG":
  12.                     Logging.log.Debug(txt);
  13.                     break;
  14.                 }
  15.  
  16.             }
  17.  
  18.         }
  19.  
My question is: as the code stands right now, I thread might have acquired the lock on the call to the logging, but a second thread might have come along and modified the method parameters "txt" and "type", right? Is there a way of locking the entire method?

I think that another option could be to create a class to hold the txt and type and pass the object to the method
Expand|Select|Wrap|Line Numbers
  1. public void LogInfo(LogText lt)
  2.         {
  3.             lock (lt)
  4.             {
  5.                 switch (lt.type)
  6.                 {
  7.                     case "ERROR":
  8.                     Logging.log.Error(lt.txt);
  9.                     break;
  10.  
  11.                     case "DEBUG":
  12.                     Logging.log.Debug(lt.txt);
  13.                     break;
  14.                 }
  15.             }
  16.  
  17.         }
  18.  
Or just locking the logger
Expand|Select|Wrap|Line Numbers
  1. class Logging
  2. {
  3. public static readonly ILog log = LogManager.GetLogger(typeof(Logging));
  4. Logging() {}
  5. public string Initialize()
  6. {
  7. .....
  8. }
  9. }
  10.  
thus when I called it from another class I do:
Expand|Select|Wrap|Line Numbers
  1. lock(Logging.log)
  2. {
  3. Logging.log.Info("hopefully there is a lock in the log right now ...");
  4. }
  5.  
Anyone knows what will be the proper way of doing this, if ANY of the ones I have mentioned? I am new to threading and feel a bit confused

Cheers
Feb 27 '09 #1
9 10378
tlhintoq
3,525 Recognized Expert Specialist
I've looked at, but not played with Log4Net. Instead I just do my own logging. In my function I raise an event with the log text. My logger is subscribed to the event. Thus it is listening for the next item to log, not being commanded to log *now*. Could something similar work for you? Raise a custom event with the logging data so that a single method then funnels the events to Log4Net?
Feb 27 '09 #2
mldisibio
190 Recognized Expert New Member
At the heart of the problem, no matter what logging API you use, is the fact that a single text stream is being accessed by more than one thread.
Locking is a good start, but remember
Expand|Select|Wrap|Line Numbers
  1. lock(someLocker){do logging}
means that any entering the "do logging" block will only proceed when the previous block is completely finished. Effectively, you will block logging threads one at a time, undermining the purpose of multi-threading.

There could be several solutions, including creating an "asynchrono us" Appender in log4net, but at a high level I would recommend what tlhintoq said with one addition:

If you set up an event that your logging object can listen to, your classes will fire a "LogTextIsReady " type of event and then carry on their task. The logging listener alone then becomes responsible for maintaining the synchronous access to the textstream when asynchronous writes are requested.
(Before I go on, let me mention that you will want to try to make the "LogTextIsReady " event as globally accessible as possible so that you are not repeating the same event in all your individual task classes. Use an interface or perhaps a static class or singleton object.)

At a basic design, your logging listener really just needs a thread signal, such as an System.Threadin g.AutoResetEven t. This is called a EventWaitHandle and allows an operation to proceed only when the previous thread or block of code finishes and tells the signal that the next block or thread may proceed.

In the case of a logger, each write method will call "WaitOne()" - meaning wait until the previous write is finished. When it finishes writing, it calls "Set()" to let the signal know to allow the next thread to start.
So your logger (which can still be a log4net logger) will be queuing up texts to write to the stream, one at a time, but because your logger is event driven, the classes and threads which called the listener do not need to wait for the event handler to complete.

By following this model, you will probably then only have one logger instance, which means you lose the log4net "named logger" and implicit tracing feature. If that is important to your application, as mentioned you can try encapsulating the above thread control into a custom Appender or Forwarder.
Feb 28 '09 #3
inxanu
9 New Member
Many thanks for your input...It has been really helpfull. I will have to think about changing the logging. But one thing that intrigues me:

At present I am locking the logger

Expand|Select|Wrap|Line Numbers
  1. lock(Logging.log)
yet i still got this error:

log4net:ERROR [FileAppender] Unable to acquire lock on file d:\logfiles\
WSFileCopier.lo g. The process cannot access the file 'd:\logfiles\WS FileCopier.log' because it is being used by another process.

This is my log4net appender in the config file:
Expand|Select|Wrap|Line Numbers
  1.     <appender name="RollingFileAppender" type="log4net.Appender.FileAppender">
  2.       <file value="d:\logfiles\WSFileCopier.log" />
  3.       <appendToFile value="true" />
  4.       <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
  5.       <layout type="log4net.Layout.PatternLayout">
  6.         <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
  7.       </layout>
  8.     </appender>
  9.  
Also my log4net appender has been configured using the minimal locking which allows multiple processes to write to the same file (eventhough at this point I am only using one...) so, why am I getting this?
Mar 2 '09 #4
mldisibio
190 Recognized Expert New Member
Not sure why. You might try removing your lock altogether just to see if it is your own lock that is causing the access denial. Does this error happen before even the first write, or is something being written to file, and this happens when a second process attempts to write?

Don't forget, locking just says: "you can't have access to this object until the lock is released." That does not mean the caller will wait for it to be released...you need the WaitHandle mechanism to actually make a thread wait for a lock to be released. So while locking the logger makes sure that no two processes are accessing the stream at the same time, it does not force a thread to wait. Therefore, as soon as the second call attempts to access the stream, it is locked out and could easily return immediately with a message "cannot acquire lock."

Of course, it could also be something silly, like another text editor or application which has an exclusive lock on your log file...this is unlikely but it happens sometimes.

Finally, some authors will recommend...alt hough it is not a hard and fast rule...that you not lock on your object doing the work, but rather on a separate object whose sole purpose is to server as a lock. So instead of
Expand|Select|Wrap|Line Numbers
  1. lock(Logging.log){...}
do (at global or static level)
Expand|Select|Wrap|Line Numbers
  1. object loggingLocker = new object();
  2.  
and in any code block:
Expand|Select|Wrap|Line Numbers
  1. lock(loggingLocker){log.WriteInfo()...etc}
Mar 2 '09 #5
inxanu
9 New Member
"Does this error happen before even the first write, ..." --> No
"or is something being written to file, and this happens when a second process attempts to write?" --> No, I do not have any more processes writting to this file, or at least I shouldn't. I am using the lock()... I will create a global lock as you suggest.

Also
"Don't forget, locking just says: "you can't have access to this object until the lock is released."

I have to create up to 100 threads to do different jobs. Once a thread finishes its job, it updates their status. The thread status info is being held in an ArrayList called jobsToDo. At present I was just using a lock (without any signalling) thinking that the lock already synchronized the threads

Expand|Select|Wrap|Line Numbers
  1. public void UpdateJobList(int jobid)
  2.         {
  3.            //Update jobList
  4.             lock (jobsToDo)
  5.             {
  6.                 bool bFound = false;
  7.                 //Find the job on the list and update it
  8.                 foreach (Jobs j in jobsToDo)
  9.                 {
  10.                     if (j.JobId == jobid)
  11.                     {
  12.                         bFound = true;
  13.                         j.ThreadId = -1;
  14.                         j.Status = "Finish";
  15.                         Logging.log.Debug("Job id \"" + j.JobId + "\" status has been updated to \"Finish\"");
  16.             Thread.Sleep(5000); //just to be sure that more than one thread will reach this method while
  17.                         //one thread in in here doing its job.
  18.                         break;
  19.                     }
  20.                 }
  21.                 if (!bFound)
  22.                 {
  23.                     Logging.log.Error("Could not found job id \"" + jobid + "\" in job list");
  24.                 }
  25.             }
  26.         }
  27.  
  28.  
Now, I am checking the log and everythings seems to be fine. How can that be!? Please note how thread Job 2, Job 3, Job 4 arrive to the lock statement, and they wait for it (or at least they seem to do that) untill Job 1 releases the lock, then Job 2 goes in and updates it is status, then after 5 sec, Job 3 goes in ...and so on...this is the expected behaviour I want...However, it seems that a lock by itself should not produced this output right? HELP! please, I really need to understand why this is happening...

Log:
Expand|Select|Wrap|Line Numbers
  1. 2009-03-02 18:53:04,498 [Job 1] DEBUG ClassLibrary1.Logging - Going to update job list for job id "1"
  2. 2009-03-02 18:53:04,498 [Job 1] DEBUG ClassLibrary1.Logging - Job id "1" status has been updated to "Finish"
  3. 2009-03-02 18:53:05,483 [9] DEBUG ClassLibrary1.Logging - Job Id 2 has been started
  4. 2009-03-02 18:53:05,498 [Job 2] DEBUG ClassLibrary1.Logging - Going to update job list for job id "2"
  5. 2009-03-02 18:53:06,498 [9] DEBUG ClassLibrary1.Logging - Job Id 3 has been started
  6. 2009-03-02 18:53:06,498 [Job 3] DEBUG ClassLibrary1.Logging - Going to update job list for job id "3"
  7. 2009-03-02 18:53:07,498 [9] DEBUG ClassLibrary1.Logging - Job Id 4 has been started
  8. 2009-03-02 18:53:07,498 [Job 4] DEBUG ClassLibrary1.Logging - Going to update job list for job id "4"
  9. 2009-03-02 18:53:08,514 [9] DEBUG ClassLibrary1.Logging - Job Id 5 has been started
  10. 2009-03-02 18:53:08,514 [Job 5] DEBUG ClassLibrary1.Logging - Going to update job list for job id "5"
  11. 2009-03-02 18:53:09,498 [Job 2] DEBUG ClassLibrary1.Logging - Job id "2" status has been updated to "Finish"
  12. 2009-03-02 18:53:09,530 [9] DEBUG ClassLibrary1.Logging - Job Id 6 has been started
  13. 2009-03-02 18:53:09,530 [Job 6] DEBUG ClassLibrary1.Logging - Going to update job list for job id "6"
  14. 2009-03-02 18:53:10,530 [9] DEBUG ClassLibrary1.Logging - Job Id 7 has been started
  15. 2009-03-02 18:53:10,530 [Job 7] DEBUG ClassLibrary1.Logging - Going to update job list for job id "7"
  16. 2009-03-02 18:53:11,530 [9] DEBUG ClassLibrary1.Logging - Job Id 8 has been started
  17. 2009-03-02 18:53:11,545 [Job 8] DEBUG ClassLibrary1.Logging - Going to update job list for job id "8"
  18. 2009-03-02 18:53:12,530 [9] DEBUG ClassLibrary1.Logging - Job Id 9 has been started
  19. 2009-03-02 18:53:12,545 [Job 9] DEBUG ClassLibrary1.Logging - Going to update job list for job id "9"
  20. 2009-03-02 18:53:13,545 [9] DEBUG ClassLibrary1.Logging - Job Id 10 has been started
  21. 2009-03-02 18:53:13,561 [Job 10] DEBUG ClassLibrary1.Logging - Going to update job list for job id "10"
  22. 2009-03-02 18:53:14,498 [Job 3] DEBUG ClassLibrary1.Logging - Job id "3" status has been updated to "Finish"
  23.  
Mar 2 '09 #6
mldisibio
190 Recognized Expert New Member
I think you are good. Let me explain why I think this works. Mind you, I am not an absolute expert or authority on the subject.

In your previous example, you were locking on the logger itself (Logging.log). Since this object owns the access to the log file, a lock on it basically locks out the file as well, no matter how access rights are configured initially.
So probably your second and third job come along, attempt to get a handle to Logging.log or its underlying file, and are told "sorry, I'm locked" so they return with "cannot access file."

In your more recent example, you are locking on the ArrayList (which by the way has some inherent thread safety built in). The logger itself is not locked. So Job 2 and Job 3 come and are told: "Wait, you can enter this method "UpdateJobL ist" as soon as the ArrayList is available." By the time they are allowed to call on the logger itself, the file has released its previous write lock.

You have the simplest locking model and it seems to work fine. I would leave it alone. Signalling would add some robustness...fo r example, if your application needed to terminate, you might be able to check if some log writes were still pending before terminating completely...bu t you can add those enhancements later.

For a great reference to threading and locking, I highly recommend:
http://www.albahari.com/threading/ [Threading in C# by Albahari]
Mar 2 '09 #7
mldisibio
190 Recognized Expert New Member
@mldisibio
You proved that what I said is not entirely correct. How about if I just quote an expert...(sourc e Albahari - same link as above):

The lock statement (aka Monitor.Enter / Monitor.Exit) is one example of a thread synchronization construct. While lock is suitable for enforcing exclusive access to a particular resource or section of code, there are some synchronization tasks for which it's clumsy or inadequate, such as signaling a waiting worker thread to begin a task.

The Win32 API has a richer set of synchronization constructs, and these are exposed in the .NET framework via the EventWaitHandle , Mutex and Semaphore classes. Some are more useful than others: the Mutex class, for instance, mostly doubles up on what's provided by lock, while EventWaitHandle provides unique signaling functionality.
Mar 2 '09 #8
inxanu
9 New Member
Hi mldisibio,

I did in fact read through the information you suggest (Albahari) thats why I thought that by locking the arraylist i was taking care of the thread synchronization . Why was I still unsure?
1) It is the first time I am using multithreading and ...
2) English is not my first language, thus sometimes I can misinterpret information (which now has been totally clarify, a big THANK YOU!)
3) As with the vast majority of information on internet, you are never sure the level of accuracy

Anyway, I REALLY APPRECIATE YOUR HELP :)

Now, my logging...I am going to try using a global lock to see how it goes...if i still get the "random" (I say random because I cannot pint point when it happens, also I cannot recret it) I will have to implement the logging as you suggested. I tried removing the lock on the logging but I was still getting the error.

Also you said
[quote]
you were locking on the logger itself (Logging.log). Since this object owns the access to the log file, a lock on it basically locks out the file as well, no matter how access rights are configured initially.
[quote]
If we go to the basics one moment, basically, whenever there is a static field which is being access by more than one thread, a lock should be used, right?Then,my logger log is being accessed by more than one thread, shouldnt i use a lock on it? Isnt' the fileappender the one that it is lock, and thread-safe?Isnt the fileappender something totally different than my logger?My understanding was that the minimal lock file appender allows, for instance, two different applications, each with it is on logger, to write to the same log file safely...please correct me if I am wrong

Cheers
Mar 2 '09 #9
mldisibio
190 Recognized Expert New Member
Couple of things:
1. The Log4Net API explicitly says that the FileAppender is NOT safe for multithreaded applications (which just means it does not come out of the box with thread safety...you can still build thread safety around it, as you are doing).

2. The MinimalLock configuration basically says: "for any write operation, acquire the lock to the underlying stream, write, release the lock." This means that two threads could write to the same file during the same overall job - but not at the same time! Writes still happen one after the other. But in an ExclusiveLock, the first thread would actually have to call CloseFile() before another thread could write to the same file. (Its real purpose is to allow one of those threads to move, copy or even delete the file without stopping logging entirely.)

3. Just a clarification: when you lock a primitive value, such as an int or a boolean, you are telling the runtime: "do not allow any caller to change this value until I release the lock on it." So a very simple example:
Expand|Select|Wrap|Line Numbers
  1. static int MyInt;
  2. static void SaveWorldIfTwo(){
  3. MyInt = 2;
  4. if((2/MyInt) == 1) SaveWorld();
  5. }
If MyInt is accessed by multiple threads, then without locking, another thread can change MyInt to zero between the call "MyInt = 2" and "2/MyInt" leading to a "division by zero" exception and the world not being saved.

However, when you lock on an object or you lock a block of code, then the focus is not on preserving a primitive value, but rather on not letting other code have access to that object or block of code until the lock is released. In some cases, you might even cause a thread to hang because you have locked an object (such as a logger) and perhaps in the case of third party libraries or in an event driven model, other classes need to access it before it exits your lock, but they cannot.

4. Finally, in terms of the relationship of the log4net ILog, Appender and such, those are great questions I am not qualified to answer. The API makes them appear to be completely separate objects, but it is quite possible they are each abstractions which have underlying dependencies. And in the case of classes which access file streams, it is very likely that the stream locking is shared among the different API layers.
Mar 3 '09 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

10
2332
by: gianguz | last post by:
The question is about the possible use of inlining to improve performance in a heavy multithreading environment (200+ threads). If we have to work with applications in which threads aren't I/O bounded or user-time bounded (i.e. windows based applications) but they are concurrently involved in the execution of the same parallelized task (i.e. a matrix-matrix multiplication), we must ensure that the advantage obtained by the parallelization...
16
8493
by: Robert Zurer | last post by:
Can anyone suggest the best book or part of a book on this subject. I'm looking for an in-depth treatment with examples in C# TIA Robert Zurer robert@zurer.com
7
4137
by: Shapiro | last post by:
I have a scenario where I log a resquest to a database table and update the request with a corresponding response including the response time. I am using an HttpModule to do this. My challenge is how to corelate the response to a corresponding request. I am looking for a sure proof threadsafe way to corelate a response to a coresponding request message. Two things that concerns me:-
2
1661
by: SStory | last post by:
Here is the situation. I want to display Icons, Type of file etc from a file extension. Upon initial program load I may only need icons for certain files. But other operations will require showing all filetypes and icons. I have an object that has extension, desc (like Word Document) and then icon, which is nothing to start with. I have a collection object of these and when it is initialized it goes to
55
3299
by: Sam | last post by:
Hi, I have a serious issue using multithreading. A sample application showing my issue can be downloaded here: http://graphicsxp.free.fr/WindowsApplication11.zip The problem is that I need to call operations on Controls from a delegate, otherwise it does not work. However each time I've done an operation, I must update the progressbar and progresslabel, but this cannot be done in the delegate as it does not work.
5
2483
by: sandy82 | last post by:
Whats actuallly multithreading is ... and how threading and multithreading differ . Can any1 guide how multithreading is used on the Web .. i mean a practical scenario in which u use multithreading online using C# .
0
1257
by: denis.cornehl | last post by:
Hi, I have an unusual Problem with DB2. It is DB2 Version 7 and Fixpack 13 under Windows. We have written an application server which is accessing db2 via c++ and the cli interface. We used IBM Visual Age as our compiler, because we had to support OS/2. Now we ported it this year to windows and the microsoft-compiler (V8).
2
2253
by: Pradnya Patil | last post by:
hi , I am trying to draw ' html div-tag ' on the screen which will resemble a rectangle through vb.net code. I want it to be drawn faster...so I introduced multithreading using Threadpool. I divided the complete drawing into 3 parts..1st will be done by main thread and other two are done in these procedures - <1LongTimeTask <2LongTimeTask2 I have invoked the threads using below method. **************
2
2326
by: lizii | last post by:
At the moment i am trying to write into a richtextbox using the Rtf call from another richtextbox. However realising that richtextbox do not have multithreading - i know i need to invoke this item and make it multithreaded safe. But i cannot find a single good example of how to do this. The richtextbox i am trying to update is on one form - the richtextbox which has the information to update it with is on another. I understand that i...
0
8421
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8325
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8742
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8621
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7354
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6177
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5643
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
2
1971
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1734
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.