2014-02-14 4 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

Почему вы не используете ConcurrentDictionary .NET4? Трудная работа по обеспечению безопасности потоков в словарях уже выполнена. Ваш код будет намного чище и менее подвержен ошибкам. Возможно, это решает вашу проблему, может быть, нет. (Вы до сих пор не описаны симптомы «не работает». Работает ли это как однопоточных приложений? Врезаться ли? Приводит ли это неправильные данные?)

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()'. –

Смежные вопросы