2014-02-14 75 views
-1

我正在编写多线程程序,以舒适的格式读取和查看Apache日志文件。它可以工作,但它在单核处理器上无法正常工作。我认为错误在哪里,但我不知道我需要改变什么。假设在评论中写入了错误。多线程程序在单核处理器上无法正常工作

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.IO; 
using System.Threading; 
using System.Windows.Forms; 
using System.Data; 
using System.Text.RegularExpressions; 

namespace lab2Form 
{ 
    class LogStruct 
    { 
     public Dictionary<string, ulong> domainName; 
     public Dictionary<string, ulong> URL; 
     public Dictionary<string, ulong> domainData; 
     public Dictionary<string, ulong> errorCodes; 

     public LogStruct() 
     { 
      domainName = new Dictionary<string, ulong> { }; 
      URL = new Dictionary<string, ulong> { }; 
      domainData = new Dictionary<string, ulong> { }; 
      errorCodes = new Dictionary<string, ulong> { }; 
     } 
    } 

    class CLogParser 
    { 
     LogStruct m_logStruct; 

     public CLogParser() 
     { 
      m_logStruct = new LogStruct(); 
     } 

     public void ThreadProc(object param) 
     { 
      string logName = (string)param; 

      StreamReader file; 
      try 
      { 
       file = new StreamReader(logName); 
      } 
      catch 
      { 
       return; 
      } 
      string line; 
      while ((line = file.ReadLine()) != null)//may be,something wrong here 
      { 
       var space_pos = line.IndexOf(' '); 
       if (space_pos > 0) 
       { 
        string[] parameters = line.Split(new Char[] { ' '}, StringSplitOptions.RemoveEmptyEntries); 
        string domainName = parameters[0]; 
        bool isMainPage = (parameters[4] == "\"-\"") ? true : false; 
        string relativePageAddress = (isMainPage) ? "/" : parameters[5]; 
        Regex reg = new Regex(" \\d+"); 
        MatchCollection matches = reg.Matches(line); 
        string errorCode = matches[1].Value; 
        ulong pageSize = (matches.Count > 2) ? Convert.ToUInt64(matches[2].Value) : 0; 
        string fullAdress = domainName + relativePageAddress; 
        string fullErrCode = domainName + errorCode; 

        if (m_logStruct.domainName.ContainsKey(domainName)) 
        { 
         lock (m_logStruct.domainName) 
         { 
          m_logStruct.domainName[domainName]++; 
         } 
         lock (m_logStruct.domainData) 
         { 
          m_logStruct.domainData[domainName] += pageSize; 
         } 
         if (m_logStruct.URL.ContainsKey(fullAdress)) 
         { 
          lock (m_logStruct.URL) 
          { 
           m_logStruct.URL[fullAdress]++; 
          } 
         } 
         else 
         { 
          lock (m_logStruct.URL) 
          { 
           m_logStruct.URL.Add(fullAdress, 1); 
          } 
         } 
         if (m_logStruct.errorCodes.ContainsKey(fullErrCode)) 
         { 
          lock (m_logStruct.errorCodes) 
          { 
           m_logStruct.errorCodes[fullErrCode]++; 
          } 
         } 
         else 
         { 
          lock (m_logStruct.errorCodes) 
          { 
           m_logStruct.errorCodes.Add(fullErrCode, 1); 
          } 
         } 
        } 
        else 
        { 
         lock (m_logStruct.domainName) 
         { 
          m_logStruct.domainName.Add(domainName, 1); 
         } 
         lock (m_logStruct.URL) 
         { 
          m_logStruct.domainData.Add(domainName, pageSize); 
         } 
         lock (m_logStruct.domainData) 
         { 
          m_logStruct.URL.Add(fullAdress, 1); 
         } 
         lock (m_logStruct.errorCodes) 
         { 
          m_logStruct.errorCodes.Add(fullErrCode, 1); 
         } 
        } 

       } 
      } 
     } 

     public void ShowData(ref DataGridView dmRequests, ref DataGridView URL, ref DataGridView dmData, ref DataGridView errorCodes) 
     { 
      List<KeyValuePair<string, ulong>> dmReqList = new List<KeyValuePair<string, ulong>>(); 
      List<KeyValuePair<string, ulong>> urlReqList = new List<KeyValuePair<string, ulong>>(); 
      List<KeyValuePair<string, ulong>> dmDataList = new List<KeyValuePair<string, ulong>>(); 
      List<KeyValuePair<string, ulong>> errCodesList = new List<KeyValuePair<string, ulong>>(); 

      lock (m_logStruct.domainName)`enter code here` 
      { 
       dmReqList = m_logStruct.domainName.ToList(); 
      } 
      lock(m_logStruct.URL) 
      { 
       urlReqList = m_logStruct.URL.ToList(); 
      } 
      lock(m_logStruct.domainData) 
      { 
       dmDataList = m_logStruct.domainData.ToList(); 
      } 
      lock(m_logStruct.errorCodes) 
      { 
       errCodesList = m_logStruct.errorCodes.ToList(); 
      } 

      dmRequests.DataSource = dmReqList.OrderBy(x => x.Key).ToList(); 
      URL.DataSource = urlReqList.OrderBy(x => x.Key).ToList(); 
      dmData.DataSource = dmDataList.OrderBy(x => x.Key).ToList(); 
      errorCodes.DataSource = errCodesList.OrderBy(x => x.Key).ToList(); 
     } 
    } 
} 
+5

你有什么证据表明它不起作用在单核处理器上? – Nilzor

+0

'while((line = file.ReadLine())!= null)'是一个本地文件,所以绝对不是问题。 –

回答

0

为什么不使用.NET4的ConcurrentDictionary?确保字典中线程安全的努力已经完成。你的代码会更干净,更不容易出错。也许它解决了你的问题,也许它不会。 (你还没有描述“不工作”的症状,它是否作为单线程应用程序运行?它会崩溃吗?它会产生错误的数据吗?)

class LogStruct 
{ 
    public ConcurrentDictionary<string, ulong> domainName; 
    public ConcurrentDictionary<string, ulong> URL; 
    public ConcurrentDictionary<string, ulong> domainData; 
    public ConcurrentDictionary<string, ulong> errorCodes; 

    public LogStruct() 
    { 
     domainName = new ConcurrentDictionary<string, ulong> { }; 
     URL = new ConcurrentDictionary<string, ulong> { }; 
     domainData = new ConcurrentDictionary<string, ulong> { }; 
     errorCodes = new ConcurrentDictionary<string, ulong> { }; 
    } 
} 

class CLogParser 
{ 
    LogStruct m_logStruct; 

    public CLogParser() 
    { 
     m_logStruct = new LogStruct(); 
    } 

    public void ThreadProc(object param) 
    { 
     string logName = (string)param; 

     StreamReader file; 
     try 
     { 
      file = new StreamReader(logName); 
     } 
     catch 
     { 
      return; 
     } 
     string line; 
     while ((line = file.ReadLine()) != null)//may be,something wrong here 
     { 
      var space_pos = line.IndexOf(' '); 
      if (space_pos > 0) 
      { 
       string[] parameters = line.Split(new Char[] { ' '}, StringSplitOptions.RemoveEmptyEntries); 
       string domainName = parameters[0]; 
       bool isMainPage = (parameters[4] == "\"-\"") ? true : false; 
       string relativePageAddress = (isMainPage) ? "/" : parameters[5]; 
       Regex reg = new Regex(" \\d+"); 
       MatchCollection matches = reg.Matches(line); 
       string errorCode = matches[1].Value; 
       ulong pageSize = (matches.Count > 2) ? Convert.ToUInt64(matches[2].Value) : 0; 
       string fullAdress = domainName + relativePageAddress; 
       string fullErrCode = domainName + errorCode; 

       if (m_logStruct.domainName.ContainsKey(domainName)) 
       { 
        m_logStruct.domainName[domainName]++; 
        m_logStruct.domainData[domainName] += pageSize; 
        m_logStruct.URL.AddOrUpdate(fullAdress, 1, (key, oldVal) => 
        { 
         m_logStruct.URL[fullAdress]++; 
         return m_logStruct.URL[fullAdress]; 
        }); 

        m_logStruct.errorCodes.AddOrUpdate(fullErrCode, 1, (key, oldVal) => 
        { 
         m_logStruct.errorCodes[fullErrCode]++; 
         return m_logStruct.errorCodes[fullErrCode]; 
        }); 
       } 
       else 
       { 
        m_logStruct.domainName.AddOrUpdate(domainName, 1, ShallNeverHappen); 
        m_logStruct.domainData.AddOrUpdate(domainName, pageSize, ShallNeverHappen); 
        m_logStruct.URL.AddOrUpdate(fullAdress, 1, ShallNeverHappen); 
        m_logStruct.errorCodes.AddOrUpdate(fullErrCode, 1, ShallNeverHappen); 
       } 
      } 
     } 
    } 

    public ulong ShallNeverHappen(String key, ulong existingVal) 
    { 
     throw new InvalidOperationException("This method is not expected to be called"); 
    } 
} 
+0

有趣。我会在稍后尝试。 – user3242084

1

您正以多种方式从多线程访问共享状态,其中至少有一个是作者。

例子:

if (m_logStruct.URL.ContainsKey(fullAdress)) //unsynchronized read 

螺纹的规则说,你不能安全地做到这一点。

我看不出你标记的行应该出现什么问题。该流是线程局部的。它没有被用在一种高尚的方式。

+0

可能是,错误不在这一行,我假设,在关键部分(锁)或读取一个核心处理器上的文件时可能出现什么错误 – user3242084

+1

这是一个错误,但仅仅是因为'm_logStruct.URL.Add ()'。他们都必须在'lock()'中。 –