Блокировка с помощью конструкторов, вызывающих нулевую ссылку? - PullRequest
2 голосов
/ 11 июля 2011

Итак, сегодня я столкнулся со странной проблемой - у меня было простое создание экземпляра внутри критической секции блокировки, и оно выдавало исключение нулевой ссылки, когда я вручную перетаскивал следующую строку для выполнения. Для иллюстрации:

public class SearchEngineOptimizationParser
{
    protected static ConcurrentDictionary<string, SearchEngineOptimizationInfo> _referralInformation = null;
    protected static DateTime _lastRecordingDate;
    protected static object _lockRecordingObject = new object();

    protected static Dictionary<string, string> _searchProviderLookups = null;

    static SearchEngineOptimizationParser()
    {
        _referralInformation = new ConcurrentDictionary<string, SearchEngineOptimizationInfo>();
        _lastRecordingDate = DateTime.Now;

        _searchProviderLookups = new Dictionary<string, string>();
        _searchProviderLookups.Add("google.com", "q");
        _searchProviderLookups.Add("yahoo.com", "p");
        _searchProviderLookups.Add("bing.com", "q");
    }

    public SearchEngineOptimizationParser()
    {

    }

    public virtual void ParseReferrer(Uri requestUrl, NameValueCollection serverVariables, ISession session)
    {
        string corePath = requestUrl.PathAndQuery.SmartSplit('?')[0].ToLower();

        string referrer = serverVariables["HTTP_REFERER"];

        if (!string.IsNullOrWhiteSpace(referrer))
        {
            NameValueCollection queryString = HttpUtility.ParseQueryString(referrer);

            string dictionaryKey = session.AffiliateID + "|" + corePath;

            foreach (var searchProvider in _searchProviderLookups)
            {
                if (referrer.Contains(searchProvider.Key))
                {
                    if (queryString[searchProvider.Value] != null)
                    {
                        string keywords = queryString[searchProvider.Value];

                        SearchEngineOptimizationInfo info = new SearchEngineOptimizationInfo
                        {
                            Count = 1,
                            CorePath = corePath,
                            AffiliateId = session.AffiliateID,
                            Keywords = keywords
                        };

                        _referralInformation.AddOrUpdate(dictionaryKey, info, (key, oldValue) =>
                        {
                            oldValue.Count++;
                            return oldValue;
                        });

                        break;
                    }
                }
            }
        }

        if (DateTime.Now > _lastRecordingDate.AddHours(1))
        {
            lock (_lockRecordingObject)
            {
                if (DateTime.Now > _lastRecordingDate.AddHours(1))
                {
                    SearchEngineKeywordRepository repository = new SearchEngineKeywordRepository();

                    List<KeyValuePair<string, SearchEngineOptimizationInfo>> currentInfo = _referralInformation.ToList();

                    Action logData = () =>
                    {
                        foreach (var item in currentInfo)
                            repository.LogKeyword(item.Value);
                    };

                    Thread logThread = new Thread(new ThreadStart(logData));
                    logThread.Start();

                    _lastRecordingDate = DateTime.Now;
                    _referralInformation.Clear();
                }
            }
        }
    }

РЕДАКТИРОВАТЬ: Обновлен реальный объект

public class SearchEngineKeywordRepository
{
    public virtual void LogKeyword(SearchEngineOptimizationInfo keywordInfo)
    {
        LogSearchEngineKeywords procedure = new LogSearchEngineKeywords();
        procedure.Execute(keywordInfo.CorePath, keywordInfo.AffiliateId, keywordInfo.Keywords, keywordInfo.Count);
    }
}

В целом, я хочу делать это «что-то» только каждый час (в контексте веб-приложения, которое получает много трафика). Я бы остановил свой первый оператор if, а затем перешел к следующей строке для выполнения внутри второго оператора if. При этом инициализация экземпляра SomeObject вызовет исключение нулевой ссылки. У него был полностью 100% конструктор по умолчанию - я даже не указал его.

Однако, когда я позволю коду пройти естественным образом, он будет выполняться без проблем. По какой-то причине кажется, что когда я пропустил вызов блокировки в критическую секцию, чтобы просто протестировать выполнение этого кода, это вызвало все виды ошибок.

Мне любопытно узнать, почему это так; Я понимаю, что ключевое слово lock является просто синтаксическим сахаром для блока Monitor.Enter(o) try / finally, но похоже, что при вызове конструктора происходило что-то еще.

У кого-нибудь есть идеи?

РЕДАКТИРОВАТЬ: я добавил фактический код к этому. Я могу воспроизвести это по своему желанию, но я все еще не понимаю, почему это происходит. Я попытался скопировать этот код в другое решение, и проблема, похоже, не возникает.

1 Ответ

1 голос
/ 11 июля 2011

Я пытался воспроизвести вашу ситуацию, но, как и ожидал, не смог.Я пробовал и 2.0 и 4.0 время выполнения, в 32- и 64-битном режиме (отладка иногда ведет себя по-разному в x64).

Является ли приведенный код упрощением?Вы проверили все свои предположения?Я так понимаю, вы пропускаете 3 строки кода, как операторы if, так и блокировку?В этом случае даже установка нулевого объекта блокировки не приводит к описанному вами исключению.

(Если для _lockRecordingObject установлено значение null, при выходе из области lock ArgumentNullException)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...