多线程程序在单核处理器上无法正常工作

时间:2014-02-14 10:02:10

标签: c# multithreading

我正在编写多线程程序,以便以舒适的形式阅读和查看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();
        }
    }
} 

2 个答案:

答案 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");
    }
}