Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
U
uniset2
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
UniSet project repositories
uniset2
Commits
778fce6f
Commit
778fce6f
authored
Jul 06, 2016
by
Pavel Vainerman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(UMessageQueue): вариант реализации на atmic-ах, заложил тест для очереди сообщений.
parent
76921f15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
171 additions
and
67 deletions
+171
-67
UMessageQueue.h
include/UMessageQueue.h
+33
-49
UniSetObject.h
include/UniSetObject.h
+0
-10
UMessageQueue.cc
src/ObjectRepository/UMessageQueue.cc
+0
-0
UniSetObject.cc
src/ObjectRepository/UniSetObject.cc
+0
-7
mq-test.cc
tests/MQPerfTest/mq-test.cc
+12
-0
Makefile.am
tests/Makefile.am
+2
-1
test_mqueue.cc
tests/test_mqueue.cc
+123
-0
uniset2.files
uniset2.files
+1
-0
No files found.
include/UMessageQueue.h
View file @
778fce6f
...
@@ -17,44 +17,36 @@
...
@@ -17,44 +17,36 @@
#ifndef UMessageQueue_H_
#ifndef UMessageQueue_H_
#define UMessageQueue_H_
#define UMessageQueue_H_
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
#include <
queue
>
#include <
atomic
>
#include <vector>
#include <vector>
#include <memory>
#include <memory>
#include "Mutex.h"
#include "MessageType.h"
#include "MessageType.h"
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
typedef
std
::
shared_ptr
<
UniSetTypes
::
VoidMessage
>
VoidMessagePtr
;
typedef
std
::
shared_ptr
<
UniSetTypes
::
VoidMessage
>
VoidMessagePtr
;
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
/*! \class UMessageQueue
/*! \class UMessageQueue
* Очередь сообщений.
* Очередь сообщений.
* \warning Очередь рассчитана на МНОГО ПИСАТЕЛЕЙ и ОДИН(!) читатель. Т.е. чтение должно быть из одного потока!
* Сообщения извлекаются из очереди в порядке приоритета сообщения. При одинаковом приоритете - в порядке поступления в очередь.
*
*
* Максимальное ограничение на размер очереди сообщений задаётся функцией setMaxSizeOfMessageQueue().
* Чтобы избежать работы с mutex, очередь построена по принципу циклического буфера,
*
* c использованием atomic-переменных и попыткой реализовать LockFree работу.
* Контроль переполения очереди осуществляется в двух местах push и receiveMessage.
* Есть указатель на текущую позицию записи (wp) и есть "догоняющий его" указатель на позицию чтения (rp).
* При переполнении очереди, происходит автоматическая очистка в два этапа.
* Если rp догоняет wp - значит новых сообщений нет.
* Первый: производиться попытка "свёртки" сообщений.
* Из очереди все повторяющиеся
* - SensorMessage
* - TimerMessage
* - SystemMessage
* Если это не помогло, то производиться второй этап "чистки":
* Из очереди удаляется MaxCountRemoveOfMessage сообщений.
* Этот парамер задаётся при помощи setMaxCountRemoveOfMessage(). По умолчанию 1/4 очереди сообщений.
*
*
* Очистка реализована в функции cleanMsgQueue();
* При этом место под очередь(буффер) резервируется сразу.
* Счётчики сделаны (uint) монотонно растущими.
* Основные идеи:
* - счётчики постоянно увеличиваются
* - каждый пишущий поток пишет в новое место
* - читающий счётчик тоже монотонно растёт
* - реальная позиция для записи или чтения рассчитывается как (pos%size) этим и обеспечивается цикличность.
*
*
* \warning Т.к. при фильтровании SensorMessage не смотрится значение,
* Максимальное ограничение на размер очереди сообщений задаётся функцией setMaxSizeOfMessageQueue().
* то при удалении сообщений об изменении аналоговых датчиков очистка может привести
* к некорректной работе фильрующих алгоритмов работающих с "выборкой" последних N значений.
* (потому-что останется одно последнее)
*
*
*
ОПТИМИЗАЦИЯ N1:
*
Контроль переполения очереди осуществляется в push и в top;
*
Для того, чтобы функции push() и top() реже "сталкавались" на mutex-е очереди сообщений.
*
Если очередь переполняется, то сообщения ТЕРЯЮТСЯ!
*
Сделано две очереди сообщений. Одна очередь сообщений наполняется в push() (с блокировкой mutex-а),
*
При помощи функции setLostStrategy() можно установить стратегию что терять
*
а вторая (без блокировки) обрабатывается в top(). Как только сообщения заканчиваются в
*
lostNewData - в случае переполнения теряются новые данные (т.е. не будут помещаться в очередь)
*
top() очереди меняются местами (при захваченном mutex)
.
*
lostOldData - в случае переполнения очереди, старые данные затираются новыми
.
*/
*/
class
UMessageQueue
class
UMessageQueue
{
{
...
@@ -71,8 +63,13 @@ class UMessageQueue
...
@@ -71,8 +63,13 @@ class UMessageQueue
void
setMaxSizeOfMessageQueue
(
size_t
s
);
void
setMaxSizeOfMessageQueue
(
size_t
s
);
size_t
getMaxSizeOfMessageQueue
();
size_t
getMaxSizeOfMessageQueue
();
void
setMaxCountRemoveOfMessage
(
size_t
m
);
enum
LostStrategy
size_t
getMaxCountRemoveOfMessage
();
{
lostOldData
,
// default
lostNewData
};
void
setLostStrategy
(
LostStrategy
s
);
// ---- Статистика ----
// ---- Статистика ----
/*! максимальное количество которое было в очереди сообщений */
/*! максимальное количество которое было в очереди сообщений */
...
@@ -87,37 +84,24 @@ class UMessageQueue
...
@@ -87,37 +84,24 @@ class UMessageQueue
return
stCountOfQueueFull
;
return
stCountOfQueueFull
;
}
}
// функция определения приоритетного сообщения для обработки
typedef
std
::
vector
<
VoidMessagePtr
>
MQueue
;
struct
VoidMessageCompare
:
public
std
::
binary_function
<
VoidMessagePtr
,
VoidMessagePtr
,
bool
>
{
bool
operator
()(
const
VoidMessagePtr
&
lhs
,
const
VoidMessagePtr
&
rhs
)
const
;
};
typedef
std
::
priority_queue
<
VoidMessagePtr
,
std
::
vector
<
VoidMessagePtr
>
,
VoidMessageCompare
>
MQueue
;
protected
:
protected
:
/
*! Чистка очереди сообщений */
/
/ заполнить всю очередь указанным сообщением
void
cleanMsgQueue
(
MQueue
&
q
);
void
mqFill
(
const
VoidMessagePtr
&
v
);
private
:
private
:
MQueue
*
wQ
=
{
nullptr
};
// указатель на текущую очередь на запись
MQueue
mqueue
;
MQueue
*
rQ
=
{
nullptr
};
// указатель на текущую очередь на чтение
std
::
atomic_uint
wpos
=
{
0
};
// позиция на запись
std
::
atomic_uint
rpos
=
{
0
};
// позиция на чтение
MQueue
mq1
,
mq2
;
std
::
atomic_uint
mpos
=
{
0
};
// текущая позиция последнего элемента (max position) (реально добавленного в очередь)
LostStrategy
lostStrategy
=
{
lostOldData
};
/*! размер очереди сообщений (при превышении происходит очистка) */
/*! размер очереди сообщений (при превышении происходит очистка) */
size_t
SizeOfMessageQueue
=
{
2000
};
size_t
SizeOfMessageQueue
=
{
2000
};
/*! сколько сообщений удалять при очисте */
size_t
MaxCountRemoveOfMessage
=
{
500
};
/*! замок для блокирования совместного доступа к очереди */
UniSetTypes
::
uniset_rwmutex
qmutex
;
// статистическая информация
// статистическая информация
size_t
stMaxQueueMessages
=
{
0
};
/*!< Максимальное число сообщений хранившихся в очереди */
size_t
stMaxQueueMessages
=
{
0
};
/*!< Максимальное число сообщений хранившихся в очереди */
size_t
stCountOfQueueFull
=
{
0
};
/*!< количество переполнений очереди сообщений */
size_t
stCountOfQueueFull
=
{
0
};
/*!< количество переполнений очереди сообщений */
...
...
include/UniSetObject.h
View file @
778fce6f
...
@@ -195,16 +195,6 @@ class UniSetObject:
...
@@ -195,16 +195,6 @@ class UniSetObject:
return
mqueue
.
getMaxSizeOfMessageQueue
();
return
mqueue
.
getMaxSizeOfMessageQueue
();
}
}
void
setMaxCountRemoveOfMessage
(
size_t
m
)
{
mqueue
.
setMaxCountRemoveOfMessage
(
m
);
}
inline
size_t
getMaxCountRemoveOfMessage
()
{
return
mqueue
.
getMaxCountRemoveOfMessage
();
}
inline
bool
isActive
()
inline
bool
isActive
()
{
{
return
active
;
return
active
;
...
...
src/ObjectRepository/UMessageQueue.cc
View file @
778fce6f
This diff is collapsed.
Click to expand it.
src/ObjectRepository/UniSetObject.cc
View file @
778fce6f
...
@@ -160,14 +160,7 @@ void UniSetObject::initObject()
...
@@ -160,14 +160,7 @@ void UniSetObject::initObject()
if
(
sz
>
0
)
if
(
sz
>
0
)
mqueue
.
setMaxSizeOfMessageQueue
(
sz
);
mqueue
.
setMaxSizeOfMessageQueue
(
sz
);
int
maxremove
=
conf
->
getArgPInt
(
"--uniset-object-maxcount-remove-message"
,
conf
->
getField
(
"MaxCountRemoveOfMessage"
),
sz
/
4
);
if
(
maxremove
>
0
)
mqueue
.
setMaxCountRemoveOfMessage
(
maxremove
);
// workingTerminateTimeout = conf->getArgPInt("--uniset-object-working-terminate-timeout",conf->getField("WorkingTerminateTimeout"),2000);
uinfo
<<
myname
<<
"(init): SizeOfMessageQueue="
<<
mqueue
.
getMaxSizeOfMessageQueue
()
uinfo
<<
myname
<<
"(init): SizeOfMessageQueue="
<<
mqueue
.
getMaxSizeOfMessageQueue
()
<<
" MaxCountRemoveOfMessage="
<<
mqueue
.
getMaxCountRemoveOfMessage
()
<<
endl
;
<<
endl
;
}
}
// ------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------
...
...
tests/MQPerfTest/mq-test.cc
View file @
778fce6f
#include <string>
#include <string>
#include <iostream>
#include <iostream>
#include <assert.h>
#include <thread>
#include <thread>
#include <atomic>
#include <atomic>
#include "UMessageQueue.h"
#include "UMessageQueue.h"
...
@@ -58,6 +59,17 @@ int main(int argc, const char** argv)
...
@@ -58,6 +59,17 @@ int main(int argc, const char** argv)
// чтобы не происходило переполнение
// чтобы не происходило переполнение
mq
.
setMaxSizeOfMessageQueue
(
COUNT
+
1
);
mq
.
setMaxSizeOfMessageQueue
(
COUNT
+
1
);
// сперва просто проверка что очередь работает.
{
SensorMessage
sm
(
100
,
2
);
TransportMessage
tm
(
std
::
move
(
sm
.
transport_msg
())
);
mq
.
push
(
tm
);
auto
msg
=
mq
.
top
();
assert
(
msg
!=
nullptr
);
SensorMessage
sm2
(
msg
.
get
()
);
assert
(
sm
.
id
==
sm2
.
id
);
}
vector
<
int
>
res
;
vector
<
int
>
res
;
res
.
reserve
(
tnum
);
res
.
reserve
(
tnum
);
...
...
tests/Makefile.am
View file @
778fce6f
...
@@ -35,7 +35,8 @@ test_conftest.cc \
...
@@ -35,7 +35,8 @@ test_conftest.cc \
test_ui.cc
\
test_ui.cc
\
test_iorfile.cc
\
test_iorfile.cc
\
test_messagetype.cc
\
test_messagetype.cc
\
test_utypes.cc
test_utypes.cc
\
test_mqueue.cc
# threadtst_SOURCES = threadtst.cc
# threadtst_SOURCES = threadtst.cc
# threadtst_LDADD = $(top_builddir)/lib/libUniSet2.la ${SIGC_LIBS} $(COMCPP_LIBS)
# threadtst_LDADD = $(top_builddir)/lib/libUniSet2.la ${SIGC_LIBS} $(COMCPP_LIBS)
...
...
tests/test_mqueue.cc
0 → 100644
View file @
778fce6f
#include <catch.hpp>
// --------------------------------------------------------------------------
#include "UMessageQueue.h"
#include "MessageType.h"
#include "Configuration.h"
// --------------------------------------------------------------------------
using
namespace
std
;
using
namespace
UniSetTypes
;
// --------------------------------------------------------------------------
TEST_CASE
(
"UMessageQueue: setup"
,
"[mqueue]"
)
{
UMessageQueue
mq
;
// проверка установки размера очереди
mq
.
setMaxSizeOfMessageQueue
(
10
);
REQUIRE
(
mq
.
getMaxSizeOfMessageQueue
()
==
10
);
}
// --------------------------------------------------------------------------
TEST_CASE
(
"UMessageQueue: simple push/top"
,
"[mqueue]"
)
{
REQUIRE
(
uniset_conf
()
!=
nullptr
);
UMessageQueue
mq
;
SensorMessage
sm
(
100
,
2
);
TransportMessage
tm
(
std
::
move
(
sm
.
transport_msg
())
);
mq
.
push
(
tm
);
auto
msg
=
mq
.
top
();
REQUIRE
(
msg
!=
nullptr
);
SensorMessage
sm2
(
msg
.
get
()
);
REQUIRE
(
sm
.
id
==
sm2
.
id
);
}
// --------------------------------------------------------------------------
TEST_CASE
(
"UMessageQueue: overflow (lost old data)"
,
"[mqueue]"
)
{
REQUIRE
(
uniset_conf
()
!=
nullptr
);
UMessageQueue
mq
;
mq
.
setMaxSizeOfMessageQueue
(
1
);
mq
.
setLostStrategy
(
UMessageQueue
::
lostOldData
);
SensorMessage
sm1
(
100
,
2
);
TransportMessage
tm1
(
std
::
move
(
sm1
.
transport_msg
())
);
mq
.
push
(
tm1
);
REQUIRE
(
mq
.
size
()
==
1
);
SensorMessage
sm2
(
110
,
50
);
TransportMessage
tm2
(
std
::
move
(
sm2
.
transport_msg
())
);
mq
.
push
(
tm2
);
REQUIRE
(
mq
.
size
()
==
1
);
auto
msg
=
mq
.
top
();
REQUIRE
(
msg
!=
nullptr
);
SensorMessage
sm
(
msg
.
get
()
);
REQUIRE
(
sm
.
id
==
sm2
.
id
);
REQUIRE
(
mq
.
getCountOfQueueFull
()
==
1
);
}
// --------------------------------------------------------------------------
TEST_CASE
(
"UMessageQueue: overflow (lost new data)"
,
"[mqueue]"
)
{
REQUIRE
(
uniset_conf
()
!=
nullptr
);
UMessageQueue
mq
;
mq
.
setMaxSizeOfMessageQueue
(
1
);
mq
.
setLostStrategy
(
UMessageQueue
::
lostNewData
);
SensorMessage
sm1
(
100
,
2
);
TransportMessage
tm1
(
std
::
move
(
sm1
.
transport_msg
())
);
mq
.
push
(
tm1
);
REQUIRE
(
mq
.
size
()
==
1
);
SensorMessage
sm2
(
110
,
50
);
TransportMessage
tm2
(
std
::
move
(
sm2
.
transport_msg
())
);
mq
.
push
(
tm2
);
REQUIRE
(
mq
.
getCountOfQueueFull
()
==
1
);
SensorMessage
sm3
(
120
,
150
);
TransportMessage
tm3
(
std
::
move
(
sm3
.
transport_msg
())
);
mq
.
push
(
tm3
);
REQUIRE
(
mq
.
size
()
==
1
);
REQUIRE
(
mq
.
getCountOfQueueFull
()
==
2
);
auto
msg
=
mq
.
top
();
REQUIRE
(
msg
!=
nullptr
);
SensorMessage
sm
(
msg
.
get
()
);
REQUIRE
(
sm
.
id
==
sm1
.
id
);
}
// --------------------------------------------------------------------------
TEST_CASE
(
"UMessageQueue: many read"
,
"[mqueue]"
)
{
REQUIRE
(
uniset_conf
()
!=
nullptr
);
UMessageQueue
mq
;
mq
.
setMaxSizeOfMessageQueue
(
1
);
mq
.
setLostStrategy
(
UMessageQueue
::
lostNewData
);
SensorMessage
sm1
(
100
,
2
);
TransportMessage
tm1
(
std
::
move
(
sm1
.
transport_msg
())
);
mq
.
push
(
tm1
);
REQUIRE
(
mq
.
size
()
==
1
);
auto
msg
=
mq
.
top
();
REQUIRE
(
msg
!=
nullptr
);
SensorMessage
sm
(
msg
.
get
()
);
REQUIRE
(
sm
.
id
==
sm1
.
id
);
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
auto
msg
=
mq
.
top
();
REQUIRE
(
msg
==
nullptr
);
}
}
// --------------------------------------------------------------------------
uniset2.files
View file @
778fce6f
...
@@ -457,6 +457,7 @@ tests/test_unixml.cc
...
@@ -457,6 +457,7 @@ tests/test_unixml.cc
tests/test_utypes.cc
tests/test_utypes.cc
tests/test_logserver.cc
tests/test_logserver.cc
tests/test_tcpcheck.cc
tests/test_tcpcheck.cc
tests/test_mqueue.cc
tests/tests-junit.xml
tests/tests-junit.xml
tests/tests.cc
tests/tests.cc
tests/tests_bad_config.xml
tests/tests_bad_config.xml
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment