I have a FreeRTOS task generator_task that generates random number once a second and stores it in buffer (this is int32_t for simplifying).
Some of generated values are magic, some are not. Task generator_task can not check if generated value is magic (requirement by design).
I have two equal FreeRTOS tasks magic_printer_task that detect button press, calls int32_t get_magic_value() and prints ButtonX pressed, magic value is %d. Function get_magic_value() must be blocking and very simple to use.
Function get_magic_value() is allowed to check if value is magic or not. Function get_magic_value() from specific task is required (by design) to monopolize reading values generated by generator_task until it gets value that treated as magic. From start and until generator_task generates magic value, get_magic_value from (example)task1 must not allow any other task to read generated values. So, other tasks should wait until task1 will get a magic value. If get_magic_value() reads non-magic value, it continues to monopolize generator and waits for next value.
Question is: How should I swap running-blocked states between two specific tasks, not giving other tasks to intercept control over those two specific tasks?
Could you help me to write lines marked with // =>>> to achieve my goals?
FreeRTOS-like C Pseudo Code:
int32_t buffer;
SemaphoreHandle_t buffer_lock;
SemaphoreHandle_t generator_attachment_lock;
bool result_accepted;
void generator_task(void* pvParams)
{
for(;;)
{
xSemaphoreTake(buffer_lock, portMAX_DELAY);
buffer = random(); buffer *= 2; buffer += random();
result_accepted = false;
// =>>> Check if some task locked generator_attachment_lock
// =>>> Give control to task who locked generator_attachment_lock
// =>>> Suspend until task who locked generator_attachment_lock wakes me
if (!result_accepted) {printf("Not accepted: %d", buffer);}
xSemaphoreGive(buffer_lock);
vTaskDelay(1000);
}
}
int32_t get_magic_value()
{
int32_t value;
xSemaphoreTake(generator_attachment_lock, portMAX_DELAY);
bool is_value_magic = false;
do {
// =>>> Suspend until generator_task wakes me
value = get_generator_value();
is_value_magic = value_is_magic(value);
result_accepted = is_value_magic;
// =>>> Wake generator_task
} while (!is_value_magic);
xSemaphoreGive(generator_attachment_lock);
return value;
}
int32_t get_generator_value()
{
int32_t value;
xSemaphoreTake(buffer_lock, portMAX_DELAY);
value = buffer;
xSemaphoreGive(buffer_lock);
return value;
}
void magic_printer_task(void* pvParams)
{
char * btnName = (char*)pvParams;
for(;;)
{
if (button_pressed(btnName)) { printf("%s magic value: %d", btnName, get_magic_value());}
vTaskDelay(50);
}
}
void main()
{
buffer_lock = xSemaphoreCreateMutex();
generator_attachment_lock = xSemaphoreCreateMutex();
xSemaphoreGive(buffer_lock);
xSemaphoreGive(generator_attachment_lock);
xTaskCreate(generator_task, ...);
xTaskCreate(magic_printer_task, ..., "Button1");
xTaskCreate(magic_printer_task, ..., "Button2");
}
//MOCK
bool value_is_magic(int32_t value) {return (value % 5 == 0); }
//MOCK
bool button_pressed(char* btnName) { return random() % 50 == 0; }
Related
I'm trying to build a tachometer in C++ for my ESP32. When I uncomment Serial.printf("outside rev: %d \n", rev); outside of the conditional it works, but when I comment it I get values that are orders of magnitude greater than they should be (700 revolutions without, vs 7 revolutions with). My best guess is that the print statement is slowing the loop() down just enough for incrementRevolutions() to toggle the global variable passedMagnet from true to false before the next loop. That would make sense, since a delay in updating passedMagnet would allow newRevCount++; to be triggered multiple times. But this is obviously something I can't debug with either print statements or step-through debugging given the time-sensitive nature of the race condition.
bool passedMagnet = true;
int incrementRevolutions(int runningRevCount, bool passingMagnet)
{
// Serial.printf("passedMagnet: %d , passingMagnet %d , runningRevCount: %d \n", passedMagnet, passingMagnet, runningRevCount);
int newRevCount = runningRevCount;
if (passedMagnet && passingMagnet)
{ //Started a new pass of the magnet
passedMagnet = false;
newRevCount++;
}
else if (!passedMagnet && !passingMagnet)
{ //The new pass of the magnet is complete
passedMagnet = true;
}
return newRevCount;
}
unsigned long elapsedTime = 0;
unsigned long intervalTime = 0;
int rev = 0;
void loop()
{
intervalTime = millis() - elapsedTime;
rev = incrementRevolutions(rev, digitalRead(digitalPin));
// Serial.printf("outside rev: %d \n", rev);
if (intervalTime > 1000)
{
Serial.printf("rev: %d \n", rev);
rev = 0;
elapsedTime = millis();
}
}
Is this a known gotcha with Arduino or C++ programming? What should I do to fix it?
I think the test is to blame. I had to rename and move things a bit to visualize the logic, sorry about that.
bool magStateOld = false; // initialize to digitalRead(digitalPin) in setup()
int incrementRevolutions(int runningRevCount, bool magState)
{
int newRevCount = runningRevCount;
// detect positive edge.
if (magState && !magStateOld) // <- was eq. to if (magState && magStateOld)
// the large counts came from here.
{
newRevCount++;
}
magStateOld = magState; // record last state unconditionally
return newRevCount;
}
You could also write it as...
int incrementRevolutions(int n, bool magState)
{
n += (magState && !magStateOld);
magStateOld = magState;
return n;
}
But the most economical (and fastest) way of doing what you want would be:
bool magStateOld;
inline bool positiveEdge(bool state, bool& oldState)
{
bool result = (state && !oldState);
oldState = state;
return result;
}
void setup()
{
// ...
magStateOld = digitalRead(digitalPin);
}
void loop()
{
// ...
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
// ...
}
It's reusable, and saves both stack space and unnecessary assignments.
If you cannot get clean transitions from your sensor (noise on positive and negative edges, you'll need to debounce the signal a bit, using a timer.
Example:
constexpr byte debounce_delay = 50; // ms, you may want to play with
// this value, smaller is better.
// but must be high enough to
// avoid issues on expected
// RPM range.
// 50 ms is on the high side.
byte debounce_timestamp; // byte is large enough for delays
// up to 255ms.
// ...
void loop()
{
// ...
byte now = (byte)millis();
if (now - debounce_timestamp >= debounce_delay)
{
debounce_timestamp = now;
rev += (int)positiveEdge(digitalRead(digitalPin), magStateOld);
}
// ...
}
I am using atomics and a circular buffer in order to implement a multi-reader threads, multi-writer threads object pool.
It is difficult to investigate because instrumenting code leads to bug vanishment !
The model
Producers (or writer threads) request an Element to the Ring in order to 'prepare' the element. When terminated, the writer thread changes the element state so a reader can 'consume' it. After that, the element becomes available again for writing.
Consumers (or reader threads) request an object to the Ring in order to 'read' the object.
After 'releasing' the object, the object is in a state::Ready state, eg available to be consume by a reader thread.
It can fail if no object is available eg the next free object in the Ring is not on state::Unused state.
The 2 classes, Element and Ring
Element :
to be written, a writer thread must successfully exchange the _state member from state::Unused to state::LockForWrite
when finished, the writer thread force the state to state::Ready (it should be the only to handle this Element)
to be read, a rader thread must successfully exchange the _state member from state::Ready to state::LockForRead
when finished, the reader thread force the state to state::Unused (it should be the only to handle this Element)
Summarized :
writers lifecycle : state::Unused -> state::LockForWrite -> state::Ready
readers lifecycle : state::Ready -> state::LockForRead -> state::Unused
Ring
has a vector of Element , seen as a circular buffer.
std::atomic<int64_t> _read, _write; are the 2 indexes used to access the elements via :
_elems[ _write % _elems.size() ] for writers,
_elems[ _read % _elems.size() ] for readers.
When a reader has successfully LockForRead an object, the _read index is incremented.
When a writer has successfully LockForWrite an object, the _write index is incremented.
The main :
We add to a vector some writers and readers threads sharing the same Ring. Each thread just try to get_read or get_write element and release them just after.
Based on Element transition everything should be fine but one can observe that the Ring at some point gets blocked like because some elements in the ring are in state state::Ready with a _write % _elems.size() index pointing on it and symetrically, some elements in the ring are in state state::Unused with a _read % _elems.size() index pointing on it ! Both = deadlock.
#include<atomic>
#include<vector>
#include<thread>
#include<iostream>
#include<cstdint>
typedef enum : int
{
Unused, LockForWrite, Ready, LockForRead
}state;
class Element
{
std::atomic<state> _state;
public:
Element():_state(Unused){ }
// a reader need to successfully make the transition Ready => LockForRead
bool lock_for_read() { state s = Ready; return _state.compare_exchange_strong(s, LockForRead); }
void unlock_read() { state s = Unused; _state.store(s); }
// a reader need to successfully make the transition Unused => LockForWrite
bool lock_for_write() { state s = Unused; return _state.compare_exchange_strong(s, LockForWrite); }
void unlock_write() { state s = Ready; _state.store(s); }
};
class Ring
{
std::vector<Element> _elems;
std::atomic<int64_t> _read, _write;
public:
Ring(size_t capacity)
: _elems(capacity), _read(0), _write(0) {}
Element * get_for_read() {
Element * ret = &_elems[ _read.load() % _elems.size() ];
if (!ret->lock_for_read()) // if success, the object belongs to the caller thread as reader
return NULL;
_read.fetch_add(1); // success! incr _read index
return ret;
}
Element * get_for_write() {
Element * ret = &_elems[ _write.load() % _elems.size() ];
if (!ret->lock_for_write())// if success, the object belongs to the caller thread as writer
return NULL;
_write.fetch_add(1); // success! incr _write index
return ret;
}
void release_read(Element* e) { e->unlock_read();}
void release_write(Element* e) { e->unlock_write();}
};
int main()
{
const int capacity = 10; // easy to process modulo[![enter image description here][1]][1]
std::atomic<bool> stop=false;
Ring ring(capacity);
std::function<void()> writer_job = [&]()
{
std::cout << "writer starting" << std::endl;
Element * e;
while (!stop)
{
if (!(e = ring.get_for_write()))
continue;
// do some real writer job ...
ring.release_write(e);
}
};
std::function<void()> reader_job = [&]()
{
std::cout << "reader starting" << std::endl;
Element * e;
while (!stop)
{
if (!(e = ring.get_for_read()))
continue;
// do some real reader job ...
ring.release_read(e);
}
};
int nb_writers = 1;
int nb_readers = 2;
std::vector<std::thread> threads;
threads.reserve(nb_writers + nb_readers);
std::cout << "adding writers" << std::endl;
while (nb_writers--)
threads.push_back(std::thread(writer_job));
std::cout << "adding readers" << std::endl;
while (nb_readers--)
threads.push_back(std::thread(reader_job));
// wait user key press, halt in debugger after 1 or 2 seconds
// in order to reproduce problem and watch ring
std::cin.get();
stop = true;
std::cout << "waiting all threads...\n";
for (auto & th : threads)
th.join();
std::cout << "end" << std::endl;
}
This "watch debugger screeshot" has been took pausing the program after running 1 second. As you can see, _read is pointing to the element 8 marked as state::Unused so no transition can unblock this state for this reader, except a writer but _write index is pointing on element 0 with state state::Ready !
My question: what did I missed in this ? Structurally I am sure the sequence is correct but I am missing some atomic trick ...
os tested : rhel5/gcc 4.1.2, rhel 7/gcc 4.8, win10/ms visual 2015, win10/mingw
Yann's answer is correct about the problem: your threads can create "holes" in the sequence by reading and writing elements out-of-order if there's a delay between the read/write lock and the increment of the index. The fix is to verify that the index has not changed between the initial read and the increment, a la:
class Element
{
std::atomic<state> _state;
public:
Element():_state(Unused){ }
// a reader need to successfully make the transition Ready => LockForRead
bool lock_for_read() {
state s = Ready;
return _state.compare_exchange_strong(s, LockForRead);
}
void abort_read() { _state = Ready; }
void unlock_read() { state s = Unused; _state.store(s); }
// a reader need to successfully make the transition Unused => LockForWrite
bool lock_for_write() {
state s = Unused;
return _state.compare_exchange_strong(s, LockForWrite);
}
void abort_write() { _state = Unused; }
void unlock_write() { state s = Ready; _state.store(s); }
};
class Ring
{
std::vector<Element> _elems;
std::atomic<int64_t> _read, _write;
public:
Ring(size_t capacity)
: _elems(capacity), _read(0), _write(0) {}
Element * get_for_read() {
auto i = _read.load();
Element * ret = &_elems[ i % _elems.size() ];
if (ret->lock_for_read()) {
// if success, the object belongs to the caller thread as reader
if (_read.compare_exchange_strong(i, i + 1))
return ret;
// Woops, reading out of order.
ret->abort_read();
}
return NULL;
}
Element * get_for_write() {
auto i = _write.load();
Element * ret = &_elems[ i % _elems.size() ];
if (ret->lock_for_write()) {
// if success, the object belongs to the caller thread as writer
if (_write.compare_exchange_strong(i, i + 1))
return ret;
// Woops, writing out of order.
ret->abort_write();
}
return NULL;
}
void release_read(Element* e) { e->unlock_read();}
void release_write(Element* e) { e->unlock_write();}
};
You do not have atomic section around the increment of the two shared counters _read and _write.
That looks bad to me, you could switch another element without meaning to.
Imagine this scenario,
1 reader R1 and 1 writer W are happily cooperating.
Reader 2 executes : Element * ret = &_elems[ _read.load() % _elems.size() ];
and gets pushed off the cpu.
Now R1 and W are still playing together, so the positions of _read and _write are now arbitrary w.r.t. the element ret that R2 is pointing.
Now at some point R2 gets scheduled, and it so happens that *ret_ is readable (again possibly, R1 and W went around the block a few times).
Ouch, as you see, we will read it, and increment "_read", but _read has no relation to _ret. This creates kind of holes, elements that have not been read, but that are below _read index.
So, make critical sections to ensure that increment of _read/_write is done in the same semantic step as the actual lock.
Describtion of the problem:
we need to call a function in extern process as fast as possible. Boost interprocess shared memory is used for communication. The extern process is either mpi master or a single executable. The calculation time of the function lies between 1ms and 1s. The function should be called up to 10^8-10^9 times.
I've tried a lot of possibilities, but I still have some problems with each of them. Here I introduce two of best working implementations
Version 1 ( using intreprocess conditions )
Main-process
bool calculate(double& result, std::vector<double> c){
// data_ptr is a structure in shared memoty
data_ptr_->validCalculation = false;
bool timeout = false;
// write data (cVec_ is a vector in shared memory )
cVec_->clear();
for (int i = 0; i < c.size(); ++i)
{
cVec_->push_back(c[i]);
}
// cond_input_data is boost interprocess condition
data_ptr_->cond_input_data.notify_one();
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
// lock slave process
scoped_lock<interprocess_mutex> lock_output(data_ptr_->mutex_output);
// wait till data calculated
timeout = !(data_ptr_->cond_output_data.timed_wait(lock_output, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
Extern process runs a while-loop ( till abort condition is fullfilled)
do {
scoped_lock<interprocess_mutex> lock_input(data_ptr_->mutex_input);
boost::system_time const waittime = boost::get_system_time() + boost::posix_time::seconds(maxWaitTime_in_sec);
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime)); // true if timeout, false if no timeout
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_function_here(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
data_ptr_->cond_output_data.notify_one();
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
This is best working version, but sometimes it holds up, if the calculation time is short (~1ms). I assume, it happens, if main-process reaches
data_ptr_->cond_input_data.notify_one();
earlier, than extern process is waiting on
timeout = !(data_ptr_->cond_input_data.timed_wait(lock_input, waittime));
waiting condition. So we have probably some kind of synchronisation problem.
Second condition does not help ( i.e. wait only if input data not set, similar to the anonymous condition example with message_in flag). Since, it is still possible, that one process notify the other one, before the second one is waiting for notification.
Version 2 ( using boolean flag and while loop with some delay )
Main-process
bool calculate(double& result, std::vector<double> c){
data_ptr_->validCalculation = false;
bool timeout = false;
// write data
cVec_->clear();
for (int i = 0; i < c.size(); ++i) //Insert data in the vector
{
cVec_->push_back(c[i]);
}
// this is the flag in shared memory used for communication
*calc_flag_ = true;
clock_t test_begin = clock();
clock_t calc_time_begin = clock();
do
{
calc_time_begin = clock();
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
// wait till data calculated
timeout = (double(calc_time_begin - test_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
} while (*(calc_flag_) && !timeout);
if (!timeout)
{
// get result
result = *result_;
return data_ptr_->validCalculation;
}
else
{
return false;
}
};
and the extern process
do {
// we wait till input data is set
wait_begin = clock();
do
{
wait_end = clock();
timeout = (double(wait_end - wait_begin) / CLOCKS_PER_SEC > maxWaitTime_in_sec);
boost::this_thread::sleep(boost::posix_time::milliseconds(while_loop_delay_m_s));
} while (!(*calc_flag_) && !(*abort_flag_) && !timeout);
if (!timeout)
{
if (!*abort_flag_) {
c.clear();
for (int i = 0; i < (*cVec_).size(); ++i) //Insert data in the vector
{
c.push_back(cVec_->at(i));
}
// calculate value
if (call_of_local_function(result, c)) { // valid calculation ?
*result_ = result;
data_ptr_->validCalculation = true;
}
}
}
//Notify the other process that the data is avalible or we dont get the input data
*calc_flag_ = false;
} while (!*abort_flag_); // while abort flag is not set, check if some values should be calculated
The problem in this version is the delay-time. Since we have calculation times close to 1ms, we have to set the delay at least to this value. For smaller delays the cpu-load is high, for higher delays we lose a lot of performance due to not necessary waiting time
Do you have an idea how to improve one of this versions? or may be there is a better solution?
thx.
this code is make queues for the the operating system
I used structures to implement my processes
and used arr_processes to handle all of this processes
and new_processes array to sort this processes according to its arrival time
but when i run this code on visual studio 2010
it produces this run time error
Run-Time Check Failure #2 - Stack around the variable arr_processes was corrupted!
this is the code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int id;
int arr_time;
int serv_time;
int deadline;
} process;
void print_process(process n);
int main()
{
process arr_processes[8];
process new_processes[8];
process real_processes[3];
process ready_processes[5];
process tmp_process[1];
int length_ready;
int i,length,j;
int length_real;
arr_processes[0].id=1;
arr_processes[0].arr_time=12;
arr_processes[0].serv_time=4;
arr_processes[0].deadline=0;
arr_processes[1].id=2;
arr_processes[1].arr_time=10;
arr_processes[1].serv_time=5;
arr_processes[1].deadline=0;
arr_processes[2].id=3;
arr_processes[2].arr_time=9;
arr_processes[2].serv_time=2;
arr_processes[2].deadline=0;
arr_processes[3].id=4;
arr_processes[3].arr_time=8;
arr_processes[3].serv_time=4;
arr_processes[3].deadline=10;
arr_processes[4].id=5;
arr_processes[4].arr_time=5;
arr_processes[4].serv_time=2;
arr_processes[4].deadline=8;
arr_processes[5].id=6;
arr_processes[5].arr_time=3;
arr_processes[5].serv_time=3;
arr_processes[5].deadline=0;
arr_processes[6].id=7;
arr_processes[6].arr_time=2;
arr_processes[6].serv_time=3;
arr_processes[6].deadline=0;
arr_processes[7].id=8;
arr_processes[7].arr_time=1;
arr_processes[7].serv_time=1;
arr_processes[7].deadline=28;
length=sizeof(arr_processes)/sizeof(arr_processes[0]);
printf("\t length of the processes=%i\n\n",length);
printf("\t The Original processes \n\n");
for(i=0;i<8;i++)
print_process(arr_processes[i]);
// now we want to sort the processes according to their arrival time
for(i=0;i<8;i++)
{
new_processes[i]=arr_processes[i];
}
for(i=0;i<length;i++)
{
for(j=0;j<length-i;j++)
{
if((new_processes[j].arr_time)>(new_processes[j+1].arr_time))
{
tmp_process[0]=new_processes[j];
new_processes[j]=new_processes[j+1];
new_processes[j+1]=tmp_process[0];
}
}
}
printf("\t The New processes \n\n");
for(i=0;i<8;i++)
print_process(new_processes[i]); // the new queue
ready_processes[0]=arr_processes[0];
ready_processes[1]=arr_processes[1];
ready_processes[2]=arr_processes[2];
ready_processes[3]=arr_processes[5];
ready_processes[4]=arr_processes[6];
length_ready=sizeof(ready_processes)/sizeof(ready_processes[0]);
// now we want to design the ready queue
for(i=0;i<length_ready;i++)
{
for(j=0;j<length_ready-i;j++)
{
if((ready_processes[j].arr_time)>ready_processes[j+1].arr_time)
{
tmp_process[0]=ready_processes[j];
ready_processes[j]=ready_processes[j+1];
ready_processes[j+1]=tmp_process[0];
}
}
}
printf("\t The ready processes \n\n");
for(i=0;i<length_ready;i++)
print_process(ready_processes[i]); // the ready queue
// now we want to design the ready real queue for the shortest deadline first
// we donnot need to check for the new proesses at each instant of time
//but we need to check for the service time from now
real_processes[0]=arr_processes[3];
real_processes[1]=arr_processes[4];
real_processes[2]=arr_processes[7];
length_real=sizeof(real_processes)/sizeof(real_processes[0]);
for(i=0;i<length_real;i++)
{
for(j=0;j<length_real-i;j++)
{
if((real_processes[j].deadline)>real_processes[j+1].deadline)
{
tmp_process[0]=real_processes[j];
real_processes[j]=real_processes[j+1];
real_processes[j+1]=tmp_process[0];
}
}
}
printf("\t The real processes \n\n");
for(i=0;i<length_real;i++)
print_process(real_processes[i]); // the ready real queue
// removed real process
process removed_real;
removed_real.id=0;
removed_real.arr_time=0;
removed_real.serv_time=0;
removed_real.deadline=0;
process running_process;
running_process.id=0;
running_process.arr_time=0;
running_process.serv_time=0;
running_process.deadline=0;
int counter=0;
int start_time;
while(counter<=28)
{
printf("when time = %i\n\n",counter);
// printf("\t The real processes when the counter=%i \n\n",counter);
// for(i=0;i<length_real;i++)
// print_process(real_processes[i]); // the ready real queue
// first we must check for the real processes
for(i=0;i<length_real;i++)
{
if((counter==real_processes[i].arr_time)
&&((real_processes[i].deadline)-counter)>=(real_processes[i].serv_time))
{
running_process=real_processes[i];
printf("The non zero deadline process is:%i\n",running_process.id);
real_processes[i]=removed_real;
start_time=counter; // real process
while(counter!=(start_time+running_process.serv_time))
{
printf("At time = %i,The Running Process is...\n",counter);
print_process(running_process);
counter++;
}
}
}
counter++;
}
return 0;
}
void print_process(process n)
{
if(n.deadline!=0)
printf("ID=%i\narr_time=%i\nserv_time=%i\ndeadline=%i\n\n\n",n.id,n.arr_time,n.serv_time,n.deadline);
else if(n.deadline==0)
printf("ID=%i\narr_time=%i\nserv_time=%i\n\n\n",n.id,n.arr_time,n.serv_time);
}
As you run out of index, here is a sort example:
for(i=0; i<length - 1; i++)
{
for(j=i + 1;j<length;j++)
{
if((new_processes[j].arr_time)>(new_processes[i].arr_time))
{
tmp_process[0]=new_processes[j];
new_processes[j]=new_processes[i] ;
new_processes[i]=tmp_process[0] ;
}
}
}
Or, you can use standard function:
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
Define a comparison function:
int compare_by_arr_time(const void* a, const void* b)
{
int a_int = ((const process*)a)->arr_time;
int b_int = ((const process*)b)->arr_time;
return a_int - b_int; // or b_int - a_int
}
And use it as follows:
qsort(new_processes,
sizeof(new_processes)/sizeof(new_processes[0]),
sizeof(new_processes[0]),
compare_by_arr_time);
You get these kinds of errors when you go out of the bounds of an array.
for(i=0;i<length;i++)
{
for(j=0;j<length-i;j++)
{
if((new_processes[j].arr_time)>(new_processes[j+1].arr_time))
{
tmp_process[0]=new_processes[j];
new_processes[j]=new_processes[j+1] ;
new_processes[j+1]=tmp_process[0] ;
}
}
}
In the first iteration, i = 0, j = 0 and j must be less than 8 - i, which is 8.
Notice the expression j+1. This expression will return values in the range of [1 ... 9] during the first iteration of the outer-most loop, and thus, you will be going out of the bounds your new_processes array.
There's your problem.
edit: This problem may also be present in the for loops that follow the first one.
Platform : Windows 7
I'm developing a project for known text cipher attack in which;
Main process creates n child processes
Child processes decrypt an encrypted string, key subspace is partitioned according to number of child processes
Communication between child processes are by a static variable
for(int i = 0; i<info.totalNumberOfChildren; i++)
{
startChild( &info.childInfoList[i]);
//_beginthread(startChild, 0, &info.childInfoList[i]);
}
Above code works fine since:
First child starts execution, the key is set as a number such as 8 for testing purposes which is within the first child's partition, so first child finds the key, reports and sets true the killSwitch.
All the other children that are created are closed even before checking the first key as the killSwitch is true.
When I however do this :
for(int i = 0; i<info.totalNumberOfChildren; i++)
{
//startChild( &info.childInfoList[i]);
_beginthread(startChild, 0, &info.childInfoList[i]);
}
I get an access violation error. What could possibly be my source of error ?
Edit: I will try to share as relevant code as I can
startChild does the following:
void startChild( void* pParams)
{
ChildInfo *ci = (ChildInfo*)pParams;
// cout<<"buraya geldi"<<endl;
ChildProcess cp(*ci);
// write to log
cp.completeNextJob();
}
childInfo holds the following :
// header file
class ChildInfo
{
public:
ChildInfo();
ChildInfo(char * encrypted, char * original, static bool killSwitch, int totalNumOfChildren, int idNum, int orjLen);
void getNextJob();
bool keyIsFound();
Des des;
void printTest();
bool stopExecution;
bool allIsChecked;
char * encyptedString;
char * originalString;
int id;
int orjStrLen;
private:
int lastJobCompleted;
int totalNumberOfChildren;
int jobDistBits;
};
completeNextJob() does the following :
void ChildProcess::completeNextJob()
{
cout<<"Child Id : "<<info.id<<endl;
// cout<<"Trying : "<<info.encyptedString<<endl; // here I got an error
char * newtrial = info.encyptedString;
char * cand = info.des.Decrypt(newtrial); // here I also get an error if I comment out
/*
cout<<"Resultant : "<<cand<<endl;
cout<<"Comparing with : "<<info.originalString<<endl;
*/
bool match = true;
for(int i = 0; i<info.orjStrLen; i++)
{
if(!(cand[i] == info.originalString[i]))
match = false;
}
if(match)
{
cout<<"It has been acknowledged "<<endl;
info.stopExecution = true;
return;
}
else
{
if(!info.keyIsFound())
{
if(!info.allIsChecked)
{
info.getNextJob();
completeNextJob();
}
else
{
}
}
else
{
}
}
}
decrypt() method does the following :
char * Des::Decrypt(char *Text1)
{
int i,a1,j,nB,m,iB,k,K,B[8],n,t,d,round;
char *Text=new char[1000];
unsigned char ch;
strcpy(Text,Text1); // this is where I get the error
i=strlen(Text);
keygen();
int mc=0;
for(iB=0,nB=0,m=0;m<(strlen(Text)/8);m++) //Repeat for TextLenth/8 times.
{
for(iB=0,i=0;i<8;i++,nB++)
{
ch=Text[nB];
n=(int)ch;//(int)Text[nB];
for(K=7;n>=1;K--)
{
B[K]=n%2; //Converting 8-Bytes to 64-bit Binary Format
n/=2;
} for(;K>=0;K--) B[K]=0;
for(K=0;K<8;K++,iB++) total[iB]=B[K]; //Now `total' contains the 64-Bit binary format of 8-Bytes
}
IP(); //Performing initial permutation on `total[64]'
for(i=0;i<64;i++) total[i]=ip[i]; //Store values of ip[64] into total[64]
for(i=0;i<32;i++) left[i]=total[i]; // +--> left[32]
// total[64]--|
for(;i<64;i++) right[i-32]=total[i];// +--> right[32]
for(round=1;round<=16;round++)
{
Expansion(); //Performing expansion on `right[32]' to get `expansion[48]'
xor_oneD(round);
substitution();//Perform substitution on xor1[48] to get sub[32]
permutation(); //Performing Permutation on sub[32] to get p[32]
xor_two(); //Performing XOR operation on left[32],p[32] to get xor2[32]
for(i=0;i<32;i++) left[i]=right[i]; //Dumping right[32] into left[32]
for(i=0;i<32;i++) right[i]=xor2[i]; //Dumping xor2[32] into right[32]
} //rounds end here
for(i=0;i<32;i++) temp[i]=right[i]; // Dumping -->[ swap32bit ]
for(;i<64;i++) temp[i]=left[i-32]; // left[32],right[32] into temp[64]
inverse(); //Inversing the bits of temp[64] to get inv[8][8]
/* Obtaining the Cypher-Text into final[1000]*/
k=128; d=0;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
d=d+inv[i][j]*k;
k=k/2;
}
final[mc++]=(char)d;
k=128; d=0;
}
} //for loop ends here
final[mc]='\0';
char *final1=new char[1000];
for(i=0,j=strlen(Text);i<strlen(Text);i++,j++)
final1[i]=final[j]; final1[i]='\0';
return(final);
}
Windows is trying to tell you why your program crashed. Please use a debugger to see what Windows is talking about. Location X is important: it should tell you whether your program is dereferencing NULL, overflowing a buffer, or doing something else. The call stack at the time of the crash is also very important.
Debugger is your best friend, try to use it and check step by step what could cause this access violation.
I think that info.encyptedString is not initialized correctly and pointing to not allocated memory, but I cant be sure because you didn't show this part of code.
And of course you must protect your shared resources (info) using some synchronization objects like critical section or mutex or semaphore.
I don't know, the basic issue seems pretty straightforward to me. You have multiple threads executing simultaneously, which access the same information via *pParams, which presumably is of type ChildInfo since that's what you cast it to. That info must be getting accessed elsewhere in the program, perhaps in the main thread. This is corrupting something, which may or may not have to do with Text1 or info.id, these errors can often be 'non-local' and hard to debug for this reason. So start mutex-protecting the entire thread (within your initial loop), and then zero in on the critical sections by trial and error, i.e. mutex-protect as small a region of code as you can get away with without producing errors.