简体   繁体   中英

Collection stacking ConcurrentQueue with multithreading

Quite a few questions/answers on this topic (only listing a couple that I found. There were many more).

  1. C# Parallel - Adding items to the collection being iterated over, or equivalent?
  2. ConcurrentQueue with multithreading

Thanks to many of them I've come up with what I'm hoping is a possible solution for my problem. I may also be overthinking it. I have an api that needs to write to a text file for logging purposes. Now the api is called N+ times and during each call, it needs to log the request. What I don't want to do is to stop the request from having to wait on the log to be recorded before returning the requested data. Now, the logs cannot just be dropped so it must also stack up on each request if the file is currently in use, using ReaderWriterLock for this. Then when the file isn't locked, I want to write the stacked logs.

I have come up with this in the hopes that it would satisfy the requirements but I think it will still cause a wait.

var wid = WindowsIdentity.GetCurrent().Token;
//add new log items
logs.Enqueue(helpers.createNewLog(requests));
string op;
while (logs.TryDequeue(out op))
{
    using (WindowsIdentity.Impersonate(wid))
    {
        //write to text file, location on shared drive
        var wrote = writers.WriteLog(op);
        //item cannot be written since file locked, add back to queue to try again
        if (!wrote)
        {
            logs.Enqueue(op);
        }
    }
 }

Logs is a global like so

private static ConcurrentQueue<string> logs = new ConcurrentQueue<string>();

I feel like something isn't right but I'm struggling with what it is and which would be the best way in order for the requirements to be meet and still work in a web farm.

In my opinion, you should use a BlockingCollection instead of the ConcurrentQueue, here is an example of how you can use it as a Producer-Consumer is the same thing you are trying to do.

Now with ASP.Net you can insert modules to intercept every request, if you want to save a log, I suggest you register a module instead of going with your approach. On your Global.asax.cs you have a Register method

public class MvcApplication : System.Web.HttpApplication
{
    public static void Register()
    {
        //registering an HttpModule
        HttpApplication.RegisterModule(typeof(LogModule));
    }

    ....
}


public class LogModule: IHttpModule
{
    public void Dispose()
    {

    }

    public void Init(HttpApplication context)
    {
        context.LogRequest += LogEvent;
    }

    private void LogEvent(object src, EventArgs args)
    {
        if (HttpContext.Current.CurrentNotification == RequestNotification.LogRequest)
        {
            if ((MvcHandler)HttpContext.Current.Handler != null)
            {
                Debug.WriteLine("This was logged!");
                //Save the information to your file
            }
        }
    }
}

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM