Could anybody tell how I can make my agents move from the Exit to the Enter block linked to the first available queue. In other words, I need an agent is teleported to a Queue block which queueSize gets zero first. Thank you for any help.enter image description here
I would use a "Wait" block right after your first queue element. I would assign a capacity of 1 to this "Wait" block. I would also create a variable of type 'Enter', let's name it emptyEnter.
On enter field of the "Wait" block, use the following:
if( queue011.size() == 0 )
{
wait.freeAll();
emptyEnter = enter01;
}
else if( queue012.size() == 0 )
{
wait.freeAll();
emptyEnter = enter02;
}
etc.
In the On Exit field of your exit block, write the following:
emptyEnter.take(agent);
Similarly, in the On Exit field of each queue, write the following:
if(self.size() == 0 )
{
wait.freeAll();
emptyEnter = enter01;
}
Replace enter01 which the corresponding enter block for each queue element.
Each time an agent leaves a queue, if the queue is empty, the agent is freed from the wait block and sent to the proper enter block.
Let me know if this works for you.
Related
I have a C++ function which is called event based on node value change. This function involves a for loop which reads around 5000 nodes for the first time and perform some calculation on them. During a read attempt, each node is assigned a node ID by comparing their subscription ID (unique for each node). During the next event this function is called again with nodes whose values are changed. Now this same process is performed, assigning node IDs (using subscription ID) in a for loop reading those 5000 stored nodes again.
The question is, is there a better way to link these nodes IDs in the first event run so that next time this event occurs, all the nodes whose value changes do not need to be checked for their node IDs? The subscription ID is a unique number here. At present this function is event based and called very frequently, so comparing 5000 nodes every second causes its CPU load to be always up.
The code:
void SubscriptionEvent::handleEvent(EventSource *source, EventArguments *args)
{
SubscriptionEventArgs* subsArgs = static_cast<SubscriptionEventArgs*>(args);
vector<string> m_devicesReset;
if (subsArgs->eventType == SubscriptionEventArgs::VALUECHANGE)
{
AgrClient *client = static_cast<AgrClient *>(source);
OpcUa_UInt32 i = 0;
bool valueChange = false;
if(m_firstEvent == true)
{
for (i = 0; i < subsArgs->dataNotifications->length(); i++)
{
if (OpcUa_IsGood((*subsArgs->dataNotifications)[i].Value.StatusCode))
{
UaNodeId nodeId;
UaStatus status = client->getNodeIdForSubscriptionId((*subsArgs->dataNotifications)[i].ClientHandle, nodeId); //improve
}
}
}
}
}
}
The below input argument
(*subsArgs->dataNotifications)[i].ClientHandle
is the subscription ID I provide every time to get the nodeId. This last line is the code is to be improved, because the function getNodeIdForSubscriptionId() runs through a for loop to search for the nodeId for the provided subscription ID.
In my current assignment I'm having trouble figuring out how I can access this particular piece of data.
To start off, the assignment calls for data to be pulled from a file to simulate a store operating normally. The only thing is, the data being pulled is about the customer. Specifically it's when the customer enters a queue and how long it takes for the cashiers to process their order.
Right now how I have customer data stored in an array of classes.
for(int i = 0; i < entries; i++)
{
/* !!!!!IMPORTANT!!!!!
* The way this program extracts file data assumes that the file will
follow a specific format
* results will vary heavily based on how the file is set up
*
* before docking points please make sure that the file follows the format
*
* "Number of entries"
* "Customer Number", "Arrival Time", "Service Time"
* "Customer Number", "Arrival Time", "Service Time"
* "Customer Number", "Arrival Time", "Service Time"
*/
xfiles >> dataEntry;
fileData[i].setNumber(dataEntry);
//inserts a number from the file into the "number" variable in the customer class.
xfiles >> dataEntry;
fileData[i].setArrival(dataEntry);
//inserts a number from the file into the "arrival" variable in the customer class.
xfiles >> dataEntry;
fileData[i].setServTime(dataEntry);
//inserts a number from the file into the "servTime" variable in the customer class.
}
xfiles.close();
It's not included with the code but there is a line that takes in account for entries earlier in the program.
In my next block I have to queue and process customers simultaneously through a period of time. I have an idea how what I should do to queue them but I'm not too sure how I should proceed on processing them. For what I know right now I believe I might want to do a conditional statement to check if a certain customer from the array have been queued or not.
The piece of data I'm currently trying to access would be the arrival time that was stored in the class.
So something like,
fileData[i].returnArrival();
but since that class is stored in a queue I'm not sure how I would be able to access it.
Right now how I have everything queued is
for(int x = 0; x < 570; x++)
{
if(cusTime == x)
{
if(scully.isFull() = false)
scully.enqueue(fileData[cusTime]);
else if(mulder.isFull() = false)
mulder.enqueue(fileData[cusTime]);
else if(skinner.isFull() = false)
skinner.enqueue(fileData[cusTime]);
else
cout << "queues are full, disposing..\n";
}
cusTime++;
}
At first I thought it would be something like
scully.returnFront()->temp->returnClass()->fileData.returnArrival();
but I'm unsure about since temp is only a pointer declared within the queue class.
There was another suggestion from a friend of mine who suggested it would probably be something like this instead, but I ended up getting segmentation errors when I ran the code.
scully.returnFront()->returnClass().returnArrival();
I think it should be the following:
scully.returnFront().returnArrival()
Because you enqueue the items from your array. Thus, returnFront() retrieves an item on which your methods should be possible.
After discussing it a bit with the professor and TA the cause of the problem was that the return front function was returning a pointer making it more difficult to access the data within the node. A solution was to have the return front function return the Class associated with the data and have the return statement return a pointer that's pointing to the class function that returns the class stored in the node.
so
Node *returnFront();
was changed to
Customer returnFront();
changes within the function was
return front;
to
return front->returnClass();
these changes made it easier to access the Customer class data from inside the main file. So I was able to instantiate a new place holding variable for the class.
Customer scullyTemp;
And after that store the data from inside the class that was stored in the node through an assignment statement.
scullyTemp = scully.returnFront();
scullyTemp.returnArrival();
It might be a little more complicated than it needs to be, but for now it does what I need it to do.
I am trying to create an emulator for something, and in the main loop for the processor I wanted to implement a simple way to step the CPU one loop at a time (prompted by pressing Enter each loop) so I can see what instructions are being executed each step. In addition, it allows you to enter a number instead of just Enter to change the default step amount from 1 to something else (so it will skip x number of cycles and then return to 1 at a time afterwards.
The issue is that it works fine when I enter a number (skip that amount of cycles and then prompts me again each cycle), but when I just press Enter rather than entering a number I want it to default to 1 step. Instead, pressing Enter causes it to just run through the whole program without ever prompting me again. How do I make Enter == 1?
void CPU_loop()
{
...
static int step = 1;
char cmd[10];
if(step == 1)
{
if(fgets(cmd, 10, stdin) != NULL) // If you entered something other than Enter; doesn't work
{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}
else
{
--step;
}
...
}
When you press enter directly, it does not default to 1, but instead you are passing the string "\n" to std::atoi(), std::atoi() cannot be used to perform sanity check on it's input, you can use a different function for that like std::strtol() or, you can simply add
if (step == 0)
step = 1;
because when, std::atoi() takes a "\n" as input, it returns 0. Read the documentation to further understand it.
Quoting the documentation
Integer value corresponding to the contents of str on success. If the converted value falls out of range of corresponding return type, the return value is undefined. ​If no conversion can be performed, 0​ is returned.
One more thing, you could do it the c++ way using streams for input to avoid all this.
You could do:
if (fgets(cmd, 10, stdin) != NULL)
{
if (cmd[0] == '\n'){
step = 1;
}
else{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}
I have a queue and I would like to perform the following operations:
pop the first element
If the element is even, push element +1
This should go on until the queue is empty; furthermore I want to use multiple goroutines at the same time.
I am able to do for a single goroutine, but as soon as I add a while everything goes wrong, since it appears that too many goroutines are created. Even putting a else {return} will not solve the problem. Side question: why not? I get the errors:
syntax error: unexpected semicolon or newline before else
syntax error: unexpected }
Link to Playground
var list = []int{0, 1, 2, 3}
var mutex = &sync.Mutex{}
func pop(out chan int) {
mutex.Lock()
element := list[0]
fmt.Println("element is ", element)
list = list[1:]
mutex.Unlock()
out <- element
}
func push(in chan int) {
for element := range in {
if element%2 == 0 {
mutex.Lock()
list = append(list, element+1)
fmt.Println("New list is ", list)
mutex.Unlock()
}
}
}
func main() {
out := make(chan int)
fmt.Println("MAIN")
// for len(list) != 0 {
go pop(out)
go push(out)
//}
time.Sleep(2)
}
A (buffered) channel is a queue, not a stack. Hence pushing and popping don't make sense in that context.
Stacks are LIFO (last in, first out), like travel luggage – you put in last what you need first. Queues are FIFO (first in, first out), like a tube where you push marbles through.
In the context of queues, you're said to enqueue and dequeue elements.
Considering all this, this is what I interpret you'd like to do:
Create a buffered channel (buffered means that it can hold a number of elements, effectively making it a queue).
Then fill it up with a bunch of random numbers
Iterate over it and enqueue again only those that are even, adding 1 to them.
Try to implement this new algorithm.
Multiple problems with your code.
else is always on the same line as if's closing brace. Please read the Spec on this.
time.Sleep takes time.Duration as its argument, which is in nanoseconds. If you want to sleep for 2 seconds, use time.Sleep(2*time.Second).
for range in push is not needed.
Your for for just spawns millions of goroutines over and over. Goroutintes are lightweight, but not free. Add some kind of synchronisation mechanism to control how many goroutines you are running.
Here is a slightly better version. It works, even though using time.Sleep as a synchronisation mechanism is something you should never do.
I have such queue:
boost::lockfree::spsc_queue<orders_log, boost::lockfree::capacity<8192>> futOrdersUpdates;
My problem is that sometimes I deque same item several times. I've added some troubleshoot code:
while (bool dequeued = futOrdersUpdates.pop(entryItem) || !endOfTransaction)
{
if (!dequeued) {
dequeueLoger.Debug("no items, try again");
continue;
} else {
if (lastRev != 0 && entryItem.replRev == lastRev) {
dequeueLoger.Debug("duplicate item!");
}
lastRev = entryItem.replRev;
}
// further processing
The idea is - if endOfTransaction flag is not set, I should "spin", otherwise I can exit if queue is empty.
In logs I found strange things:
"no items, try again" - is NEVER appear
"duplicate item!" - IS appear.
Expected behavior:
"no items, try again" should appear sometimes - when queue is empty but endOfTransaction flag is not set
"duplicate item!" should NEVER appear
The question is - if i'm "dequee" spsc_queue correctly? Any bugs in my code?
We can't possibly know why you are getting duplicates, because we have no idea how you fill replRev. It could be a data race right there (I hope you don't do lastRev+1, e.g.).
Note that you likely never get "No items try again" because the loop is skipped entirely, e.g.:
while (bool dequeued = foo())
{
assert(dequeued); // can never be false here!
}
will never even enter the loop.
The reason you get duplicates is because you say
bool dequeued = futOrdersUpdates.pop(entryItem) || !endOfTransaction;
As you know (see your comment) this forces dequeued to be true even if no item was dequeued, because endOfTransaction has not been set yet.
The value of entryItem is unspecified at that time - but likely just contains the previous value, leading to the "duplicate" message.
For a nice demo using spsc_queue I recently gave, see this answer: Dynamic generation & safe usage of spsc_queues