Merge pull request #54 from an-tao/dev

Modify the SpinLock
This commit is contained in:
An Tao 2019-02-01 10:11:34 +08:00 committed by GitHub
commit 97667f358e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 33 deletions

View File

@ -13,18 +13,12 @@
#pragma once
#include <drogon/config.h>
#include <shared_mutex>
#include <atomic>
#include <thread>
namespace drogon
{
#if (CXX_STD > 14)
typedef std::shared_mutex SharedMutex;
#else
typedef std::shared_timed_mutex SharedMutex;
#endif
enum HttpStatusCode
{
//rfc2616-6.1.1
@ -115,22 +109,4 @@ enum HttpMethod
Invalid
};
class SpinLock
{
public:
SpinLock(std::atomic_flag &flag) : _flag(flag)
{
while (_flag.test_and_set(std::memory_order_acquire))
{
}
}
~SpinLock()
{
_flag.clear(std::memory_order_release);
}
private:
std::atomic_flag &_flag;
};
} // namespace drogon

View File

@ -17,6 +17,7 @@
#include "HttpRequestImpl.h"
#include "HttpResponseImpl.h"
#include "HttpAppFrameworkImpl.h"
#include "SpinLock.h"
using namespace drogon;
@ -219,7 +220,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
{
HttpResponsePtr responsePtr;
{
SpinLock guard(ctrlBinderPtr->_binderMtx);
SimpleSpinLock guard(ctrlBinderPtr->_binderMtx);
responsePtr = ctrlBinderPtr->_responsePtr;
}
@ -282,7 +283,7 @@ void HttpControllersRouter::doControllerHandler(const CtrlBinderPtr &ctrlBinderP
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
{
SpinLock guard(ctrlBinderPtr->_binderMtx);
SimpleSpinLock guard(ctrlBinderPtr->_binderMtx);
ctrlBinderPtr->_responsePtr = resp;
}
}

View File

@ -50,6 +50,7 @@ class HttpControllersRouter : public trantor::NonCopyable
std::vector<std::shared_ptr<HttpFilterBase>> _filters;
std::vector<size_t> _parameterPlaces;
std::map<std::string, size_t> _queryParametersPlaces;
//std::atomic<bool> _binderMtx = ATOMIC_VAR_INIT(false);
std::atomic_flag _binderMtx = ATOMIC_FLAG_INIT;
std::shared_ptr<HttpResponse> _responsePtr;
};

View File

@ -14,6 +14,7 @@
#include "HttpAppFrameworkImpl.h"
#include "HttpResponseImpl.h"
#include "SpinLock.h"
#include <drogon/HttpViewBase.h>
#include <drogon/HttpViewData.h>
#include <drogon/HttpAppFramework.h>
@ -350,14 +351,14 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
_httpStringDate = now.microSecondsSinceEpoch() / MICRO_SECONDS_PRE_SEC;
auto newDate = getHttpFullDate(now);
{
SpinLock lock(*_httpStringMutex);
SimpleSpinLock lock(*_httpStringMutex);
_httpString = std::make_shared<std::string>(*_httpString);
memcpy((void *)&(*_httpString)[_datePos], newDate, strlen(newDate));
return _httpString;
}
}
{
SpinLock lock(*_httpStringMutex);
SimpleSpinLock lock(*_httpStringMutex);
return _httpString;
}
}
@ -393,7 +394,7 @@ std::shared_ptr<std::string> HttpResponseImpl::renderToString() const
httpString->append(*_bodyPtr);
if (_expriedTime >= 0)
{
SpinLock lock(*_httpStringMutex);
SimpleSpinLock lock(*_httpStringMutex);
_datePos = datePos;
_httpString = httpString;
}

View File

@ -41,7 +41,7 @@ class HttpResponseImpl : public HttpResponse
_leftBodyLength(0),
_currentChunkLength(0),
_bodyPtr(new std::string()),
_httpStringMutex(new std::atomic_flag())
_httpStringMutex(new std::atomic_flag)
{
_httpStringMutex->clear();
}

View File

@ -15,6 +15,7 @@
#include "FiltersFunction.h"
#include "HttpSimpleControllersRouter.h"
#include "HttpAppFrameworkImpl.h"
#include "SpinLock.h"
using namespace drogon;
@ -126,7 +127,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
HttpResponsePtr responsePtr;
{
//Maybe update the _responsePtr, so we use shared_lock to protect;
SpinLock guard(item._mutex);
SimpleSpinLock guard(item._mutex);
responsePtr = item._responsePtr;
}
if (responsePtr && (responsePtr->expiredTime() == 0 || (trantor::Date::now() < responsePtr->creationDate().after(responsePtr->expiredTime()))))
@ -154,7 +155,7 @@ void HttpSimpleControllersRouter::doControllerHandler(SimpleControllerRouterItem
//cache the response;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->makeHeaderString();
{
SpinLock guard(item._mutex);
SimpleSpinLock guard(item._mutex);
item._responsePtr = resp;
}
}

View File

@ -56,6 +56,7 @@ class HttpSimpleControllersRouter : public trantor::NonCopyable
std::vector<int> _validMethodsFlags;
std::shared_ptr<HttpSimpleControllerBase> _controller;
std::shared_ptr<HttpResponse> _responsePtr;
//std::atomic<bool> _mutex = ATOMIC_VAR_INIT(false);
std::atomic_flag _mutex = ATOMIC_FLAG_INIT;
};
std::unordered_map<std::string, SimpleControllerRouterItem> _simpCtrlMap;

86
lib/src/SpinLock.h Normal file
View File

@ -0,0 +1,86 @@
/**
* SpinLock.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <atomic>
#include <thread>
#include <emmintrin.h>
#define LOCK_SPIN 2048
namespace drogon
{
class SpinLock
{
public:
inline SpinLock(std::atomic<bool> &flag)
: _flag(flag)
{
const static int cpu = std::thread::hardware_concurrency();
int n, i;
while (1)
{
if (!_flag.load() && !_flag.exchange(true, std::memory_order_acquire))
{
return;
}
if (cpu > 1)
{
for (n = 1; n < LOCK_SPIN; n <<= 1)
{
for (i = 0; i < n; i++)
{
//__asm__ __volatile__("rep; nop" ::: "memory"); //pause
_mm_pause();
}
if (!_flag.load() && !_flag.exchange(true, std::memory_order_acquire))
{
return;
}
}
}
std::this_thread::yield();
}
}
inline ~SpinLock()
{
_flag.store(false, std::memory_order_release);
}
private:
std::atomic<bool> &_flag;
};
class SimpleSpinLock
{
public:
inline SimpleSpinLock(std::atomic_flag &flag)
: _flag(flag)
{
while (_flag.test_and_set(std::memory_order_acquire))
{
//__asm__ __volatile__("rep; nop" ::: "memory"); //pause
_mm_pause();
}
}
inline ~SimpleSpinLock()
{
_flag.clear(std::memory_order_release);
}
private:
std::atomic_flag &_flag;
};
} // namespace drogon

View File

@ -22,12 +22,20 @@
#include <string>
#include <functional>
#include <iostream>
#include <mutex>
#include <shared_mutex>
namespace drogon
{
namespace orm
{
#if (CXX_STD > 14)
typedef std::shared_mutex SharedMutex;
#else
typedef std::shared_timed_mutex SharedMutex;
#endif
enum ConnectStatus
{
ConnectStatus_None = 0,