我正在编写多线程程序,以便以舒适的形式阅读和查看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();
}
}
}
答案 0 :(得分:1)
您以多种方式从多个线程访问共享状态,其中至少有一个是作者。
示例:
if (m_logStruct.URL.ContainsKey(fullAdress)) //unsynchronized read
线程规则说你不能安全地做到这一点。
我不知道你标记的那条线应该是什么错。流是线程本地的。它并没有以一种活泼的方式使用。
答案 1 :(得分: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");
}
}