I have written this code that simulates a parking system, however I have a problem when I have to reuse a struct that contains a messageQueue to my carthread. The problem occurs when I try to communicate to the handler for exit with ID_CAR_IND. The struct is send as a message, so I suspect that it gets deleted before arriving, but I can't seem to grasp what is happening, and where it goes wrong. It should be noted that it is a requirement implementation that pthread is used and 3 threads are created.
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
#include <queue>
#include <time.h>
#include <unistd.h>
#include "Message.h"
#include "MsgQueue.h"
using namespace std;
enum{
ID_START_IND,
ID_ENTRY_REQ,
ID_ENTRY_CFM,
ID_CAR_IND,
ID_STAY_HERE,
ID_EXIT_REQ,
ID_EXIT_OUT,
ID_EXIT_CFM
};
//MESSAGES
struct Car : public Message
{
Car(int carID, MsgQueue* queue) : id(carID), carmq(queue){}
MsgQueue *carmq;
int id;
};
struct OpenReq : public Message
{
MsgQueue *Who_is_asking_;
};
struct CloseReq : public Message
{
MsgQueue *Who_is_asking_exit;
};
struct EntryDoorOpen : public Message{
bool result;
};
MsgQueue entryMq(20);
MsgQueue exitMq(20);
void carHandler(Car* car, unsigned id, Message* msg){
switch(id){
case ID_START_IND:
{
cout << "car " << car->id << " wants to enter" << endl;
OpenReq * req = new OpenReq();
req->Who_is_asking_ = car->carmq;
entryMq.send(ID_ENTRY_REQ, req);
}
break;
case ID_ENTRY_CFM:
{
cout << "car " << car->id << " entered parking" << endl;
entryMq.send(ID_CAR_IND);
}
break;
case ID_STAY_HERE:
{
}
break;
case ID_EXIT_CFM:
{
cout << "car " << car->id << "Left parking" << endl;
exitMq.send(ID_EXIT_OUT);
}
break;
default:
break;
}
}
void entryHandler(unsigned id, Message* msg){
OpenReq* req=static_cast<OpenReq*>(msg);
switch(id){
case ID_ENTRY_REQ:
{
cout << "Access granted. Opening entry door " << endl;
req->Who_is_asking_->send(ID_ENTRY_CFM);
}
break;
case ID_CAR_IND:
{
cout << "Closing entry door " << endl;
sleep(2);
req->Who_is_asking_->send(ID_EXIT_REQ);
}
break;
default:
break;
}
}
void exitHandler(unsigned id, Message * msg)
{
OpenReq* req = static_cast<OpenReq*>(msg);
switch(id)
{
case ID_EXIT_REQ:
{
cout << "Leaving is Granted. Opening exit door" << endl;
req->Who_is_asking_->send(ID_EXIT_CFM);
}
break;
case ID_EXIT_OUT:
{
cout << "Car has left the parkinglot" << endl;
}
break;
default:
break;
}
}
void *car(void* data){
Car *car = static_cast<Car*>(data);
car->carmq->send(ID_START_IND);
for(;;){
unsigned long id;
Message *msg = car->carmq->receive(id);
carHandler(car,id,msg);
delete(msg);
}
}
void *entry(void* data){
for(;;){
unsigned long id;
Message *msg = entryMq.receive(id);
entryHandler(id,msg);
delete(msg);
}
}
void *exit(void * data){
for(;;){
unsigned long id;
Message *msg = exitMq.receive(id);
exitHandler(id,msg);
delete(msg);
}
}
int main()
{
MsgQueue q(10);
Car carObj(1, &q);
pthread_t carThread, entryThread;
pthread_create(&carThread,nullptr,car, &carObj);
pthread_create(&entryThread,nullptr,entry, nullptr);
pthread_join(carThread,nullptr);
return 0;
}
//
// Created by stud on 11/3/19.
//
#include "MsgQueue.h"
#include "Message.h"
#include <iostream>
MsgQueue::MsgQueue(unsigned long maxSize) : maxSize_(maxSize)
{
//Init pthread funktionerne.
pthread_mutex_init(&msgmutex, NULL);
pthread_cond_init(&msgcond,NULL);
};
void MsgQueue::send(unsigned long id, Message* msg)
{
pthread_mutex_lock(&msgmutex);
while(msgqueue_.size() == maxSize_)
{
pthread_cond_wait(&msgcond, &msgmutex);
}
info besked;
besked.id = id;
besked.msg = msg;
msgqueue_.push(besked);
pthread_cond_broadcast(&msgcond);
pthread_mutex_unlock(&msgmutex);
//std::cout << "sending from id #" << id << std::endl;
};
Message* MsgQueue::receive(unsigned long&id)
{
pthread_mutex_lock(&msgmutex);
while(msgqueue_.empty())
{
pthread_cond_wait(&msgcond,&msgmutex);
}
info besked;
besked = msgqueue_.front();
id = besked.id;
msgqueue_.pop();
pthread_cond_broadcast(&msgcond);
pthread_mutex_unlock(&msgmutex);
return besked.msg;
};
MsgQueue::~MsgQueue()
{
pthread_mutex_destroy(&msgmutex);
pthread_cond_destroy(&msgcond);
};
//
// Created by stud on 11/3/19.
//
#pragma once
#include <iostream>
#include <pthread.h>
#include "Message.h"
#include <queue>
struct info : public Message
{
unsigned long id;
Message* msg;
};
class MsgQueue
{
public:
MsgQueue(unsigned long maxSize);
void send(unsigned long id, Message* msg = NULL);
Message* receive(unsigned long&id);
~MsgQueue();
private:
unsigned long maxSize_;
std::queue <info> msgqueue_;
pthread_cond_t msgcond;
pthread_mutex_t msgmutex;
};
//
//
//
#pragma once
class Message
{
public:
virtual ~Message(){};
};
The question currently lacks a few details (like details about what exactly your problem is, including any error message you get), but we can speculate some on what the problem is. Since the problem is with ID_CAR_IND, lets start by examining the handler for that message. It prints a message, then dereferences a pointer that is a property of the message. Nothing obviously wrong there.
So let's check where we create that message. It sends just the message ID. Furthere investigation shows that send takes an optional second parameter. Since it is not provided, this will be a nullptr in the message that is sent.
Since this extra message data is needed by the message handler, and not provided, this results in dereferencing a null pointer in the handler, resulting in Undefined Behavior and (typically) a crash of the program with something like an access violation error.
The solution is to pass an OpenReq object to send (like you are for the ID_START_IND message).
Consider revising the code to check or remove consecutive uses of the -> operator. There is some way in which the code cannot catch the null value.
Why don't you use OS API instead of implementing your own MsgQueue?
Related
In Android Framework, Handler are used to send messages to and receive messages from MessageQueue.
I have the following programs that implements 2 handler classes MySensor and MyReceiver (both inherit android handler). Their instances are created on different threads.
MySensor invokes sendMessage() to send the message to MessageQueue.
MyReceiver invokes handleMessage() to retrieve the message from MessageQueue.
A Looper that both MySensor and MyReceiver are bounded with will processes the messages.
"bounded with" is the word I got from some blogs that explain this concept.
#include <iostream>
#include <android/looper.h>
#include <android/handler.h>
#include <thread>
using namespace android;
enum EventType {
DIAGNOSTIC_SIGNAL,
CONTROL_SIGNAL,
STOP_SIGNAL
};
class MySensor : public Handler {
public:
MySensor(sp<Looper> looper) : Handler(looper) {}
void sendSignal(EventType event, int data) {
Message msg = obtainMessage(event, data);
sendMessage(msg);
}
};
class MyReceiver : public Handler {
public:
MyReceiver(sp<Looper> looper) : Handler(looper) {}
void handleMessage(const Message& msg) {
EventType event = (EventType) msg.what;
int data = msg.arg1;
switch (event) {
case DIAGNOSTIC_SIGNAL:
std::cout << "Received DIAGNOSTIC_SIGNAL with data: " << data << std::endl;
break;
case CONTROL_SIGNAL:
std::cout << "Received CONTROL_SIGNAL with data: " << data << std::endl;
break;
case STOP_SIGNAL:
std::cout << "Received STOP_SIGNAL with data: " << data << std::endl;
break;
default:
std::cout << "Received unknown signal with data: " << data << std::endl;
break;
}
}
};
void runSensor(sp<Looper> looper) {
MySensor sensor(looper);
sensor.sendSignal(DIAGNOSTIC_SIGNAL, 123);
sensor.sendSignal(CONTROL_SIGNAL, 456);
sensor.sendSignal(STOP_SIGNAL, 789);
}
void runReceiver(sp<Looper> looper) {
MyReceiver receiver(looper);
looper->pollOnce(-1);
}
int main() {
sp<Looper> looper = new Looper(false);
std::thread sensorThread(runSensor, looper);
std::thread receiverThread(runReceiver, looper);
sensorThread.join();
receiverThread.join();
return 0;
}
However, I don't understand:
How can MySensor and MyReceiver be bounded to the Looper, which is actually created on main thread?
How can we be sure the correct MyReceiver would receive the message ?
I also see that in some code, people use msg->sendToTarget instead of sendMessage(msg). What are differences between the two functions?
p.s: the program is written by chatGPT AI. I also asked the AI the same questions but I trust human more.
I'm a newbie in OMNeT++ and I want to make a simple broadcast mechanism where starting node sends a msg and it will broadcast it to all nodes connecting in a mesh topology. When msg reaches its destination, the msg will be deleted and does not broadcast further more. Continuously, I'm working on it from 2 days by following it's official documentation. My code is successfully simulated. But it doesn't delete the msg when it reaches to destination. I'm starting with just 25 nodes (computer) in which source node is computer0 and destination node is computer24. Tell me, where I'm wrong. Below is my source code:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
class computer : public cSimpleModule
{
protected:
virtual void forwardMessage(cMessage *msg);
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
};
Define_Module(computer);
void computer::initialize()
{
if (getIndex() == 0) {
char msgname[20];
sprintf(msgname, "msg-%d", getIndex());
cMessage *msg = new cMessage(msgname);
scheduleAt(0.0, msg);
}
}
void computer::handleMessage(cMessage *msg)
{
if (getIndex() == 24) {
EV << "Message " << msg << " arrived.\n";
delete msg;
}
else {
forwardMessage(msg);
}
}
void computer::forwardMessage(cMessage *msg)
{
int n = gateSize("gate");
int k = intuniform(0, n-1);
EV << "Forwarding message " << msg << " on gate[" << k << "]\n";
send(msg, "gate$o", k);
}
simulation snap: https://i.stack.imgur.com/a4JRQ.png
You use getIndex() method that return the position of a module in the array of modules. However, the simulation snap shows that you do not use array of modules. Therefore getIndex() returns zero for every module.
The simplest way to correct your model is to check the name of a module instead of its position, for example:
void computer::initialize()
{
// if (getIndex() == 0) {
if (isName("computer0")) {
char msgname[20];
// ...
void computer::handleMessage(cMessage *msg)
{
// if (getIndex() == 24) {
if (isName("computer24")) {
EV << "Message " << msg << " arrived.\n";
// ...
I know, this may be a lot to ask, but can anyone help me debug this code:
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
class Node : public cSimpleModule
{
private:
cMessage *out_msg;
long no_sent = 0;
long no_rcvd = 0;
cOutVector rcvdRecord;
cLongHistogram Statistics;
public:
Node();
virtual ~Node();
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
virtual void finish() override;
};
Define_Module(Node);
Node::Node()
{
out_msg = nullptr;
}
Node::~Node()
{
delete out_msg;
}
void Node::initialize()
{
out_msg = nullptr;
if (strcmp("sender", getName()) == 0) {
EV << "Scheduling first send to t=5.0s\n";
scheduleAt(5.0, out_msg);
out_msg = new cMessage("Sending Message");
}
}
void Node::handleMessage(cMessage *msg)
{
if (msg == out_msg) {
EV << "Sending message to receiver\n";
send(out_msg, "out");
out_msg = nullptr;
no_sent++;
simtime_t delay = par("delayTime");
scheduleAt(simTime() + delay, out_msg);
}
else {
out_msg = msg;
no_rcvd++;
rcvdRecord.record(out_msg);
Statistics.collect(out_msg); //what's going on here ?
}
}
void Node::finish()
{
EV << "Sent: " << no_sent << endl;
EV << "Received: " << no_rcvd << endl;
EV << "Messages sent, mean: " << Statistics.getMean() << endl;
EV << "Messages sent, standard deviation: " << Statistics.getStddev() << endl;
EV << "Messages sent, variance: " << Statistics.getVariance() << endl;
recordScalar("#sent", no_sent);
recordScalar("#received", no_rcvd);
Statistics.recordAs("Message Statistics");
}
I get the following error message:
Exercise2.cc:66:38: error: no matching function for call to
'omnetpp::cOutVector::record(omnetpp::cMessage*&)'
Exercise2.cc:67:39: error: no matching function for call to
'omnetpp::cLongHistogram::collect(omnetpp::cMessage*&)'
So I really don't know what this is supposed to tell me. Aren't these built-in functions, part of the cOutVector or cLongHistogram classes respectively?
Aren't these built-in functions, part of the cOutVector or
cLongHistogram classes respectively?
They aren't. Well, cOutVector does have a member function named record, it just can't take a cMessage * as an argument, so that specific function overload you wanted to use doesn't exist. Same with cLongHistogram and collect.
Just take a look at the documentation:
A cOutVector object can write doubles to the output vector file ...
And, by the way, what exactly do you expect to see as a "histogram of messages"? :D This comic comes to my mind...
To record the messages (not into a cOutVector), you can enable event logging. The resulting file can be visualized in the Sequence Chart tool of the IDE, see: https://docs.omnetpp.org/tutorials/tictoc/part2/#25-visualizing-on-a-sequence-chart
I've started learning POCO C++ library and I'm stuck while trying to run 2 servers in the same application (so that they can use some common runtime variables). These are 2 different servers, one of them is TCP TimeServer and the other one is simple UDP EchoServer. The code:
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Net/TCPServerParams.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/DatagramSocket.h"
#include "Poco/Timestamp.h"
#include "Poco/DateTimeFormatter.h"
#include "Poco/DateTimeFormat.h"
#include "Poco/Exception.h"
#include "Poco/Util/ServerApplication.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::TCPServer;
using Poco::Timestamp;
using Poco::DateTimeFormatter;
using Poco::DateTimeFormat;
using Poco::Util::ServerApplication;
using Poco::Util::Application;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class TimeServerConnection : public TCPServerConnection
{
public:
TimeServerConnection(const StreamSocket& s, const std::string& format) :
TCPServerConnection(s),
_format(format)
{
}
void run()
{
Application& app = Application::instance();
bool isOpen = true;
Poco::Timespan timeOut(10, 0);
unsigned char incommingBuffer[1000];
app.logger().information("SYSLOG from " + this->socket().peerAddress().toString());
while (isOpen) {
if (socket().poll(timeOut, Poco::Net::Socket::SELECT_READ) == false) {
std::cout << "TIMEOUT!" << std::endl << std::flush;
} else {
int nBytes = -1;
try {
nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer));
std::cout << incommingBuffer << std::endl;
} catch (Poco::Exception& exc) {
std::cerr << "Network error: " << exc.displayText() << std::endl;
isOpen = false;
}
if (nBytes == 0) {
std::cout << "Client closes connection!" << std::endl << std::flush;
isOpen = false;
} else {
std::cout << "Receiving nBytes: " << nBytes << std::endl << std::flush;
}
}
}
try
{
Timestamp now;
std::string dt(DateTimeFormatter::format(now, _format));
dt.append("\r\n");
socket().sendBytes(dt.data(), (int)dt.length());
}
catch (Poco::Exception& exc)
{ app.logger().log(exc); }
}
private:
std::string _format;
};
class TimeServerConnectionFactory : public TCPServerConnectionFactory
{
public:
TimeServerConnectionFactory(const std::string& format) :
_format(format)
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{ return new TimeServerConnection(socket, _format); }
private:
std::string _format;
};
class UDPServer : public Poco::Util::ServerApplication
{
public:
UDPServer(){}
~UDPServer(){}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize() { ServerApplication::uninitialize(); }
int main(const std::vector<std::string>& args)
{
unsigned short port = (unsigned short)config().getInt("udpport", 9002);
std::cout << "[UDP] Using port " << port << std::endl;
std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));
Poco::Net::SocketAddress socketaddress(Poco::Net::IPAddress(), 9001);
Poco::Net::DatagramSocket datagramsocket(socketaddress);
char buffer[1024]; // 1K byte
while (1) {
Poco::Net::SocketAddress sender;
int n = datagramsocket.receiveFrom(buffer, sizeof(buffer) - 1, sender);
buffer[n] = '\0';
std::cout << sender.toString() << ":" << buffer << std::endl;
}
return 0;
}
};
class TimeServer : public Poco::Util::ServerApplication
{
public:
TimeServer() : _helpRequested(false)
{
}
~TimeServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A server application that serves the current date and time.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
unsigned short port = (unsigned short)config().getInt("tcpport", 9911);
std::cout << "Using port " << port << std::endl;
std::string format(config().getString("TimeServer.format", DateTimeFormat::ISO8601_FORMAT));
ServerSocket svs(port);
TCPServer srv(new TimeServerConnectionFactory(format), svs);
srv.start();
std::cout << "Server started!\n";
waitForTerminationRequest();
srv.stop();
std::cout << "Server stopped!\n";
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char** argv)
{
TimeServer app;
UDPServer app2;
app.run(argc, argv);
app2.run(argc, argv);
}
In the end of code I have int main() method where I'm trying to run 2 servers. However I get assertion violation here. There is a similar question on StackOverflow, however boost is used there while I'm using plain C++, so that solution is not relevant to me.
How can I run simultaneously these 2 servers?
ServerApplication was not designed for multiple instances. What you should do is run one ServerApplication and launch TCPServer and UDPServer in that application.
Actually if you want to made like this (as you question), seperated both
tcp (a) class and
udp (b) class.
Call both in other class (c) and
define which one
(c) -> (a)
(c) -> (b)
u need to call first and when. So u need make condition and decision.
Note: give them space time before run to made poco breath. 😂
I try to write a little client-server program. A client should detect all servers running in the same LAN. I tried to implement a UDP-Broadcast with qt but my read function returns -1 all the time. If I call the dataAvailable()-function on the socket, it says that 4 bytes are available to read, but for some reason it fails to read them.
For now I'm trying to receive the broadcast on the same machine and in the same program
Here's my main:
#include <iostream>
#include <QString>
#include <QThread>
#include "../include/network.h"
using namespace std;
using namespace network;
int main () {
Network *n = new Network ();
n->broadcast("test");
if (n->dataAvailable()) {
cout << "Data available: ";
cout << n->getData().toStdString() << std::endl;
} else {
cout << "No data" << endl;
}
delete n;
}
and my Network-class:
#ifndef NETWORK
#define NETWORK
#include <QObject>
#include <QUdpSocket>
#include <iostream>
namespace network {
class Network : public QObject {
Q_OBJECT
public:
const static int BROADCAST_PORT = 52433;
explicit Network(QObject *parent = 0) {
socket = new QUdpSocket ();
socket->bind (QHostAddress::Any, BROADCAST_PORT);
}
~Network () {
delete socket;
}
bool dataAvailable () {
return socket->hasPendingDatagrams();
}
QString getData () {
if (!dataAvailable()) {
return "";
}
char *data = 0;
std::cout << socket->pendingDatagramSize() << std::endl;
std::cout << QString("recv: %1")
.arg(socket->readDatagram(data,
socket->pendingDatagramSize())).toStdString();
return QString(data);
}
void broadcast(QString data) {
QUdpSocket *broadcast = new QUdpSocket ();
broadcast->connectToHost(QHostAddress::Broadcast, BROADCAST_PORT);
std::cout << broadcast->write(data.toStdString().c_str())
<< std::endl << std::endl;
delete broadcast;
}
private:
QUdpSocket *socket;
};
}
#endif // NETWORK
the Output is the following:
4
Data available: 4
recv -1
Which means
4 Bytes are sent from the broadcast
the socket detects that 4 bytes are available
the attempt to read the 4 bytes fails
the QString returned by getData() is empty
Unfortunately I could not find any possibility to get more information on the error
You definitely need to allocate memory for reading datagram. Now you try to write it to null pointer.
// char *data = 0;
std::cout << socket->pendingDatagramSize() << std::endl;
QVector<char> buffer(socket->pendingDatagramSize()); // create buffer
std::cout << QString("recv: %1")
.arg(socket->readDatagram(buffer.data(),
socket->pendingDatagramSize())).toStdString();