Set system clock with QT on linux - linux

How would we go about changing the system time on a linux system programatically using QT widget application ?

You can use dbus to interface with timedated daemon https://www.freedesktop.org/wiki/Software/systemd/timedated/
to set time and date.
Qt provides a way to generate interface code from xml
http://doc.qt.io/qt-5/qdbusxml2cpp.html. You can get xml by introspection.
I don't like generated code formatting so I wrote interface code myself
h:
#ifndef TIMEDATE1SERVICE_H
#define TIMEDATE1SERVICE_H
#include <QObject>
#include <QString>
#include <QVariant>
#include <QtDBus>
class Timedate1Interface: public QDBusAbstractInterface
{
Q_OBJECT
Q_PROPERTY(bool CanNTP READ CanNTP)
Q_PROPERTY(bool LocalRTC READ LocalRTC)
Q_PROPERTY(bool NTP READ NTP)
Q_PROPERTY(bool NTPSynchronized READ NTPSynchronized)
Q_PROPERTY(qulonglong RTCTimeUSec READ RTCTimeUSec)
Q_PROPERTY(qulonglong TimeUSec READ TimeUSec)
Q_PROPERTY(QString Timezone READ Timezone)
public:
explicit Timedate1Interface(QObject *parent = nullptr);
bool CanNTP() const;
bool LocalRTC() const;
bool NTP() const;
bool NTPSynchronized() const;
qulonglong RTCTimeUSec() const;
qulonglong TimeUSec() const;
QString Timezone() const;
void SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction);
void SetNTP(bool useNTP, bool userInteraction);
void SetTime(qlonglong usecUTC, bool relative, bool userInteraction);
void SetTimezone(const QString &timezone, bool userInteraction);
};
#endif // TIMEDATE1SERVICE_H
cpp:
#include "timedate1service.h"
Timedate1Interface::Timedate1Interface(QObject *parent)
: QDBusAbstractInterface("org.freedesktop.timedate1", "/org/freedesktop/timedate1",
"org.freedesktop.timedate1", QDBusConnection::systemBus(), parent)
{
}
bool Timedate1Interface::CanNTP() const
{
return qvariant_cast<bool>(property("CanNTP"));
}
bool Timedate1Interface::LocalRTC() const
{
return qvariant_cast<bool>(property("LocalRTC"));
}
bool Timedate1Interface::NTP() const
{
return qvariant_cast<bool>(property("NTP"));
}
bool Timedate1Interface::NTPSynchronized() const
{
return qvariant_cast<bool>(property("NTPSynchronized"));
}
qulonglong Timedate1Interface::RTCTimeUSec() const
{
return qvariant_cast<qulonglong>(property("RTCTimeUSec"));
}
qulonglong Timedate1Interface::TimeUSec() const
{
return qvariant_cast<qulonglong>(property("TimeUSec"));
}
QString Timedate1Interface::Timezone() const
{
return qvariant_cast<QString>(property("Timezone"));
}
void Timedate1Interface::SetLocalRTC(bool localRTC, bool fixSystem, bool userInteraction)
{
call("SetLocalRTC", localRTC, fixSystem, userInteraction);
}
void Timedate1Interface::SetNTP(bool useNTP, bool userInteraction)
{
call("SetNTP", useNTP, userInteraction);
}
void Timedate1Interface::SetTime(qlonglong usecUTC, bool relative, bool userInteraction)
{
call("SetTime", usecUTC, relative , userInteraction);
}
void Timedate1Interface::SetTimezone(const QString &timezone, bool userInteraction)
{
call("SetTimezone", timezone, userInteraction);
}

You cannot do that in pure Qt. You need to use Linux (or POSIX) specific things.
And you probably should not do that, but better yet configure your entire system to use NTP (e.g. by running some NTP client...). Most Linux distributions have that already.
If you really want to set the system time (but you should not do that directly from a Qt application, since Qt applications should not run as root, but see this), read time(7) then adjtimex(2) & settimeofday(2)
You need to be root for that, so you should not do that from a Qt application. You might use setuid techniques to run some specific command or program as root. Setuid is tricky (see credentials(7), execve(2), setreuid(2)...), could open a giant security hole if misused (and making mistakes is easy), so read something about Linux programming, e.g. the old ALP.
So if you insist doing that (and it is probably wrong), write a tiny specific program in C for that and make it setuid and run that setuid-program from your Qt application (e.g. using QProcess).

I found a simple solution. As my system is very minimalist i dont want to use things like dbus. As a root or sudoer this can be execute (fairly self explainatory )-
QString string = dateTime.toString("\"yyyy-MM-dd hh:mm\"");
QString dateTimeString ("date -s ");
dateTimeString.append(string);
int systemDateTimeStatus= system(dateTimeString.toStdString().c_str());
if (systemDateTimeStatus == -1)
{
qDebug() << "Failed to change date time";
}
int systemHwClockStatus = system("/sbin/hwclock -w");
if (systemHwClockStatus == -1 )
{
qDebug() << "Failed to sync hardware clock";
}

Related

Obtaining signal names in the design (using VPI calls)

I would like to get a list of signal names in a given design hierarchy from a Verilog design using vpi. It is a simple net name browser interface from my custom tool that is written in C and Python.
How can I get a list of signal names from a Verilog design and which VPI calls I should use to walk through the design?
Any info would be greatly appreciated.
In addition to the answer already given this code walk through your hierarchy and store design object of type vpiLogic you can adapt it to your needs.
It stores the full names of the register in an unordered_map which has nice O(1) access time during simulation.
This code was developed for projects using both verilog and VHDL.
You'll also find that sometimes some IP's are protected which is handled gracefully, in addition the usage of scopes (vpiInternalScope) instead of vpiModule allows recursion inside generate statements.
It is c++ code but usage of extern "C" makes it callable from your EDA tools (tested using IUS).
#include "vhpi_user.h"
#include "vpi_user.h"
#include "vpi_user_cds.h"
#include "sv_vpi_user.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unordered_map>
extern "C" {
static std::unordered_map<int , std::string> reg_map;
#define check_verilog(scopeH) (vpi_get(vpiLanguage,scopeH) == vpiVerilog)
#define check_is_protected(scopeH) (vpi_get(vpiIsProtected,scopeH))
#define check_protected(scopeH) (vpi_get(vpiProtected,scopeH))
#define check_vhdl(scopeH) (vpi_get(vpiLanguage,scopeH) == vpiVHDL)
bool is_vpi_protected(vpiHandle scopeH) {
switch(vpi_get(vpiType, scopeH)) {
case vpiClockingBlock:
case vpiNamedBegin:
case vpiTask:
return check_is_protected(scopeH);
default: {
return check_protected(scopeH);
}
}
}
bool is_valid_scope(vpiHandle scopeH) {
switch (vpi_get(vpiType, scopeH)) {
case vpiInstance:
case vpiModule:
case vpiGenScope:
case vpiGenScopeArray:
case vpiInstanceArray:
return true;
default:
return false;
}
}
void vpi_get_reg(vpiHandle module) {
vpiHandle itr_reg, reg;
if ((itr_reg = vpi_iterate(vpiReg,module))) {
while ((reg = vpi_scan(itr_reg))) {
std::string reg_name(vpi_get_str(vpiFullLSName, reg));
vpi_printf("** Verilog register Full Name:\t%s[%d]\n",reg_name.c_str(),vpi_get(vpiSize, reg));
reg_map[(int)reg_map.size()+1] = reg_name;
}
}
}
void vhpi_get_reg(vpiHandle module) {
vhpiHandleT itr_reg, reg;
if (vhpi_get(vhpiKindP,module) == vhpiCompInstStmtK) {
if ((itr_reg = vhpi_iterator(vhpiSigDecls,module))) {
while (reg = vhpi_scan(itr_reg)) {
std::string reg_name(vhpi_get_str(vhpiFullLSNameP, reg));
vhpi_printf("** VHDL register Full LS Name:\t%s[%d]\n",reg_name.c_str(),vhpi_get(vhpiSizeP, reg));
reg_map[(int)reg_map.size()+1] = reg_name;
}
}
}
}
void walk_down(vpiHandle parentScope) {
vpiHandle subScopeI, subScopeH;
if (check_verilog(parentScope) && is_valid_scope(parentScope)) {
vpi_get_reg(parentScope);
if ((subScopeI = vpi_iterate(vpiInternalScope, parentScope))) {
while ((subScopeH = vpi_scan(subScopeI))) {
if (is_vpi_protected(subScopeH)) {
if (vpi_get(vpiType, parentScope)!= vpiGenScope)
vpi_printf("** Verilog scope %s in %s is protected \n",vpi_get_str(vpiFullLSName, subScopeH),vpi_get_str(vpiDefFile,parentScope));
else
vpi_printf("** Verilog scope %s in %s is protected \n",vpi_get_str(vpiFullLSName, subScopeH),vpi_get_str(vpiFile,subScopeH));
}
else {
walk_down(subScopeH);
}
}
}
}
else if(check_vhdl(parentScope)) {
vhpi_get_reg(parentScope);
subScopeI = vhpi_iterator(vhpiInternalRegions, parentScope);
if (subScopeI) {
while ((subScopeH = vhpi_scan(subScopeI)))
walk_down(subScopeH);
}
}
}
void navigate_mixed(const char * scope) {
reg_map.clear();
vpiHandle topScopeI, topScopeH;
vpi_printf(".........Starting register discovery \n");
if ((topScopeH = vpi_handle_by_name((PLI_BYTE8 *)scope, NULL))) {
topScopeI = vpi_iterate(vpiModule, topScopeH);
while ((topScopeH = vpi_scan(topScopeI)))
walk_down(topScopeH);
}
if ((topScopeH = vhpi_handle_by_name((PLI_BYTE8 *)scope, NULL)))
walk_down(topScopeH);
vpi_printf("Completed register discovery........\n");
}
}

memory corruption while executing my code

# include "stdafx.h"
# include <iostream>
#include <ctype.h>
using namespace std;
class a
{
protected:
int d;
public:
virtual void assign(int A) = 0;
int get();
};
class b : a
{
char* n;
public:
b()
{
n=NULL;
}
virtual ~b()
{
delete n;
}
void assign(int A)
{
d=A;
}
void assignchar(char *c)
{
n=c;
}
int get()
{
return d;
}
char* getchart()
{
return n;
}
};
class c : b
{
b *pB;
int e;
public:
c()
{
pB=new b();
}
~c()
{
delete pB;
}
void assign(int A)
{
e=A;
pB->assign(A);
}
int get()
{
return e;
}
b* getp()
{
return pB;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
c *pC=new c();
pC->assign(10);
b *p=pC->getp();
p->assignchar("a");
char *abc=p->getchart();
delete pC;
cout<<*abc<<endl;
getchar();
}
i'm a noob at c++ and was experimenting when i got to this point. I don't understand why i keep getting a memory corruption message from VS2010. I am trying to replicate a problem which is at a higher level by breaking it down into smaller bits, any help would be appreciated.
From a cursory glance, you are passing a static char array to AssignChar that cannot be deleted (ie when you type "A" into your code, its a special block of memory the compiler allocates for you).
You need to understand what assignment of a char* does (or any pointer to type). When you call n=c you are just assigning the pointer, the memory that pointer points to remains where it is. So, unless this is exactly what you meant to do, you will have 2 pointers pointing to the same block of memory.. and you need to decide which to delete (you can't delete it twice, that'd be bad).
My advice here is to start using C++, so no more char* types, use std::string instead. Using char* is C programming. Note that if you did use a std::string, and passed one to assignChars, it would copy as you expected (and there is no need to free std::string objects in your destructor, they handle all that for you).
The problem occurs when you're trying to delete pC.
When ~c() destructor calls ~b() destructor - you're trying to delete n;.
The problem is that after assignchar(), n points to a string literal which was given to it as an argument ("a").
That string is not dynamically allocated, and should not be freed, meaning you should either remove the 'delete n;' line, or give a dynamically-allocated string to assignchar() as an argument.

C++/CLI multiple errors

I am getting multiple, confusing errors when building this school assignment and am hoping for some direction on what might be the problem. I wouldn't normally write it like this, but I put everything into one file as I try to debug this. Using Visual Studios Express 2012. I'm getting over 30 errors when I build, so I'm sure there is something fundamental that I am simply overlooking. Just a suggestion please, not looking for anyone to do my homework. Thanks
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include "MessageDisplayClass.h"
#include "LogMessageClass.h"
#include "TimerEventArgs.h"
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler(/*Object^ sender, TimerEventArgs^ args*/);
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = b;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
DisplayMessageClass^ messageDisplayer = gcnew DisplayMessageClass(this);
LogMessageClass^ messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
ref class MainProgram
{
int main(array<System::String ^> ^args)
{
CustomTimerClass^ timerClass = gcnew CustomTimerClass();
DisplayMessageClass^ messageClass = gcnew DisplayMessageClass();
LogMessageClass^ logerClass = gcnew LogMessageClass();
timerClass->run();
return 0;
}
};
At the point you're trying to use the various classes, the compiler doesn't know about them yet. Move your main() function to the end of the file. Or better, split your class definitions in their own header files and then include them in your main source file.
There are other related problems too. For example, you're trying to use the TimerEventArgs class before the compiler knows about it. So you need to move the class definition up. This is why it's best to have each class in its own header file, and then include it where needed. Though it's not strictly unnecessary, if you declare/define everything in the correct order.
Other than wrong order of declarations, it looks like the problem is that the compiler doesn't recognize the ^ bit, which suggests you're not compiling as C++/CLI. Righ-click the project in Solution Explorer and go to Configuration Properties -> General, and make sure that Common Language Runtime Support is set to Common Language Runtime Support (/clr).
For the benefit of anyone else (other newbies): As it turns out, my suspicion that the problem lay in the fact that some of the classes were "#including" each other was the problem. Using forward declarations, combined with having to create a separate class altogether to act as a variable storage handler was the solution to my problem.
Here are the two classes that were giving me the biggest problem, corrected to function correctly:
/*
CustomTimerClass.h
*/
#include "StdAfx.h"
#include "LogMessageClass.h"
#include "MessageDisplayClass.h"
#include "TimerEventArgs.h"
#include "Variables.h"
//ref class MessageDisplayClass;
//ref class Variables;
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
// create instance of MessageDisplayClass and LogMessageClass
MessageDisplayClass^ messageDisplayer;
LogMessageClass^ messageLogger;
Variables^ flagVariable;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler();
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = flagVariable->Flag;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
messageDisplayer = gcnew MessageDisplayClass(this, flagVariable);
messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
/*
MessageDisplayClass serves to display a message that
represents the time at which the TimerEventArgs class is
instantiated. This time is returned through a function
of TimerEventArgs class.
*/
#pragma once
#include "stdafx.h"
#include <iostream>
#include "TimerEventArgs.h"
#include "Variables.h"
using namespace System;
ref class CustomTimerClass; // FORWARD DECLARATION HERE CAN
// ONLY BE USED FOR REFERENCE. CANNOT
// BE USED WHEN METHODS OF THE CLASS
// ARE CALLED
ref class MessageDisplayClass
{
private:
CustomTimerClass^ customTimerRef;
// Variables CLASS CREATED SOLELY TO ACT AS GO-BETWEEN BETWEEN
// MessageDisplayClass and CustomTimerClass
Variables^ variableRef;
static int counter;
public:
// constructor
MessageDisplayClass(CustomTimerClass^ CustomTimerClassInput, Variables^ variableReference)
{
customTimerRef = CustomTimerClassInput;
variableRef = gcnew Variables (CustomTimerClassInput);
}
void displayMessage(Object^ sender, TimerEventArgs^ timer)
{
counter ++;
if (counter > 0)
{
variableRef->Flag = true;
Console::WriteLine("Message: an event occured at time stamp: " + timer->EventTime);
}
}
};

How to write custom module for ebtables?

Basically, I want to write a kernel module that adds a possible filter to ebtables. Then I need to tell ebtables to use my filter on a bridge I have set up.
The reason I need to write my own module is that I want to introduce delay between consecutive packages (for some testing reason). To demonstrate, my network originally has a traffic like this:
+++-----------------+++-----------------+++-----------------+++-----------------
where + shows traffic of a package and - means no package on the line. I want to put a bridge in between so that the pattern of the packets would change to this:
+----+----+---------+----+----+---------+----+----+---------+----+----+---------
This means that I would make sure there would be a certain amount of delay between arrival of each packet.
Now I have written the following simple code which I basically took from linux-source/net/bridge/netfilter/ebt_ip.c:
static bool match(const struct sk_buff *skb, const struct xt_match_param *par)
{
printk(KERN_INFO"match called\n");
return true; // match everything!
}
static bool check(const struct xt_mtchk_param *par)
{
printk(KERN_INFO"check called\n");
return true; // pass everything!
}
static struct xt_match reg __read_mostly = {
.name = "any", // I made this up, but I tried also putting ip for example which didn't change anything.
.revision = 0,
.family = NFPROTO_BRIDGE,
.match = match,
.checkentry = check,
.matchsize = XT_ALIGN(4), // don't know what this is, so I just gave it an `int`
.me = THIS_MODULE
};
int init_module(void)
{
return xt_register_match(&reg);
}
void cleanup_module(void)
{
xt_unregister_match(&reg);
}
I successfully load the module. But it's as if it's not there. I'm not getting the logs inside match and check functions so the bridge is clearly not considering my filter. What am I doing wrong?
I have tried many combinations of loading my filter first, setting up the bridge first or setting ebtables rules first, but none of them change anything.
P.S. The bridge itself works. I am certain that ebtables is also in effect because if I add a policy to drop packages, I don't receive them on the final computer. What I can't figure out is how to tell ebtables to consider my filter also.
I got this working, not in the most elegant way, but anyway, I am writing it here for a future wanderer:
Let's say your filter name is: "any"
User-space plugin
You need headers that are not available outside the ebtables source. So, get the source code, and go to extensions folder. In the Makefile, add any to EXT_FUNC (that is targets to be built) and write the source file ebt_any.c like the following:
#include <stdio.h>
#include <getopt.h>
#include "../include/ebtables_u.h"
/*struct whatever
{
int a;
};*/
static struct option _any_opts[] =
{
{"use-any", required_argument, 0, 0},
{'\0'}
};
static void _any_help(void)
{
printf("any match options: nothing!\n");
}
static void _any_init(struct ebt_entry_match *match)
{
printf("any_init\n");
}
static void _any_check(const struct ebt_u_entry *entry, const struct ebt_entry_match *match, const char *name,
unsigned int hookmask, unsigned int time)
{
printf("any_check\n");
}
static int _any_parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match)
{
printf("any_parse: %d\n", c);
if (c == 0)
return 1;
return 0; // return true for anything
}
static int _any_compare(const struct ebt_entry_match *m1, const struct ebt_entry_match *m2)
{
/* struct whatever *w1 = (struct whatever *)m1->data;
struct whatever *w2 = (struct whatever *)m2->data;
if (w1->a != w2->a)
return 0;*/
return 1;
}
static void _any_print(const struct ebt_u_entry *entry, const struct ebt_entry_match *match)
{
printf("any_print");
}
static struct ebt_u_match _reg = {
.name = "any",
// .size = sizeof(struct whatever),
.help = _any_help,
.init = _any_init,
.parse = _any_parse,
.final_check = _any_check,
.print = _any_print,
.compare = _any_compare,
.extra_ops = _any_opts,
};
void _init(void)
{
ebt_register_match(&_reg);
}
Note: if you have data going from user-space to kernel space, write something instead of struct whatever. I have commented it out because I am not using anything.
Note: even if your program doesn't require an option (such as mine which was supposed to match everything), you need to give an option anyway because that's how ebtables knows to use your filter.
Note: some of these functions seem unnecessary, but if you don't write them, you get a "BUG: bad merge" error.
Kernel-space module
The kernel-space module is simpler:
#include <linux/netfilter/x_tables.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shahbaz Youssefi");
MODULE_ALIAS("ebt_any");
/*struct whatever
{
int a;
};*/
static bool match(const struct sk_buff *skb, const struct xt_match_param *par)
{
printk(KERN_INFO"Matching\n");
return true;
}
static bool check(const struct xt_mtchk_param *par)
{
printk(KERN_INFO"Checking\n");
return true;
}
static struct xt_match reg __read_mostly = {
.name = "any",
.match = match,
// .matchsize = sizeof(struct whatever),
.checkentry = check,
.me = THIS_MODULE
};
int init_module(void)
{
int ret = 0;
printk("Bridge initializing...\n");
ret = xt_register_match(&reg);
printk("Bridge initializing...done!\n");
return ret;
}
void cleanup_module(void)
{
printk("Bridge exiting...\n");
xt_unregister_match(&reg);
printk("Bridge exiting...done!\n");
}
Note: if you use struct whatever in user-space, you must use the same in kernel-space.
Note: unlike user-space plugin that use ebtables headers/functions, the kernel module uses xtables instead!!
Compile the module (fairly standard) and install it for automatic loading. Alternatively, you can insmod and rmmod the module yourself before adding/after removing ebtables rules.
How to make ebtables use your filter
Just add a rule that contains --use-any some_value and you're good. For example:
ebtables -A FORWARD --use-any 1 -j ACCEPT
Note: this --use-any is the option that was given in ebt_u_match reg.extra_ops (which was defined in array _any_opts) in the user space plugin.
To use a kernel module, you also need to write an appropriate plugin for the userspace program, and afterwards, insert a rule invoking it.
If you do not have any options, do not specify any .matchsize parameter in struct xt_match (equal to specifying 0).

Looking for an optimum multithread message queue

I want to run several threads inside a process. I'm looking for the most efficient way of being able to pass messages between the threads.
Each thread would have a shared memory input message buffer. Other threads would write the appropriate buffer.
Messages would have priority. I want to manage this process myself.
Without getting into expensive locking or synchronizing, what's the best way to do this? Or is there already a well proven library available for this? (Delphi, C, or C# is fine).
This is hard to get right without repeating a lot of mistakes other people already made for you :)
Take a look at Intel Threading Building Blocks - the library has several well-designed queue templates (and other collections) that you can test and see which suits your purpose best.
If you are going to work with multiple threads, it is hard to avoid synchronisation. Fortunately it is not very hard.
For a single process, a Critical Section is frequently the best choice. It is fast and easy to use. For simplicity, I normally wrap it in a class to handle initialisation and cleanup.
#include <Windows.h>
class CTkCritSec
{
public:
CTkCritSec(void)
{
::InitializeCriticalSection(&m_critSec);
}
~CTkCritSec(void)
{
::DeleteCriticalSection(&m_critSec);
}
void Lock()
{
::EnterCriticalSection(&m_critSec);
}
void Unlock()
{
::LeaveCriticalSection(&m_critSec);
}
private:
CRITICAL_SECTION m_critSec;
};
You can make it even simpler using an "autolock" class you lock/unlock it.
class CTkAutoLock
{
public:
CTkAutoLock(CTkCritSec &lock)
: m_lock(lock)
{
m_lock.Lock();
}
virtual ~CTkAutoLock()
{
m_lock.Unlock();
}
private:
CTkCritSec &m_lock;
};
Anywhere you want to lock something, instantiate an autolock. When the function finishes, it will unlock. Also, if there is an exception, it will automatically unlock (giving exception safety).
Now you can make a simple message queue out of an std priority queue
#include <queue>
#include <deque>
#include <functional>
#include <string>
struct CMsg
{
CMsg(const std::string &s, int n=1)
: sText(s), nPriority(n)
{
}
int nPriority;
std::string sText;
struct Compare : public std::binary_function<bool, const CMsg *, const CMsg *>
{
bool operator () (const CMsg *p0, const CMsg *p1)
{
return p0->nPriority < p1->nPriority;
}
};
};
class CMsgQueue :
private std::priority_queue<CMsg *, std::deque<CMsg *>, CMsg::Compare >
{
public:
void Push(CMsg *pJob)
{
CTkAutoLock lk(m_critSec);
push(pJob);
}
CMsg *Pop()
{
CTkAutoLock lk(m_critSec);
CMsg *pJob(NULL);
if (!Empty())
{
pJob = top();
pop();
}
return pJob;
}
bool Empty()
{
CTkAutoLock lk(m_critSec);
return empty();
}
private:
CTkCritSec m_critSec;
};
The content of CMsg can be anything you like. Note that the CMsgQue inherits privately from std::priority_queue. That prevents raw access to the queue without going through our (synchronised) methods.
Assign a queue like this to each thread and you are on your way.
Disclaimer The code here was slapped together quickly to illustrate a point. It probably has errors and needs review and testing before being used in production.

Resources