Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am working on a project about multithreading. Here Operation is a class which contains a type, a key, a time and an answer.
Here is my code:
#include <cstdlib>
#include <fstream>
#include <string>
#include <iomanip>
#include <pthread.h>
#include <vector>
#include "block.h"
using namespace std;
std::vector<Operation> *data;
block_bloom_filter filter(10000000, 0.01);
int ans[30000000];
void *test(void *arg)
{
int thread_id = *((int *)arg);
for (auto &op : data[thread_id])
{
if (op.type == 1)
{
filter.insert(op);
}
else
{
filter.query(op);
}
}
return 0;
}
int main(int argc, char **argv)
{
int k = atoi(argv[1]);
int *op_num = new int[k];
data = new vector<Operation>[k];
for (int i = 0; i < k; i++)
{
string tmp = "data" + to_string(i + 1) + ".in";
const char *s = tmp.c_str();
ifstream fin;
fin.open(s);
fin >> op_num[i];
//data[i] = new Operation[op_num[i]];
for (int j = 0; j < op_num[i]; j++)
{
string tmp1;
fin >> tmp1;
if (tmp1 == "insert")
{
Operation tmp2;
tmp2.type = 1;
fin >> tmp2.key >> tmp2.time;
tmp2.ans = -1;
data[i].push_back(tmp2);
}
else
{
Operation tmp2;
tmp2.type = 2;
fin >> tmp2.key >> tmp2.time;
tmp2.ans = -1;
data[i].push_back(tmp2);
}
}
fin.close();
}
auto start = std::chrono::high_resolution_clock::now();
int num_threads = k;
pthread_t *threads = new pthread_t[num_threads];
//auto **threads = new thread *[num_threads];
//pthread_t *threads = new pthread_t[k];
/*for (int i = 0; i < num_threads; i++)
{
threads[i] = new thread(test, i);
}
for (int i = 0; i < num_threads; i++)
{
threads[i]->join();
}*/
for (int i = 0; i < k; i++)
{
pthread_create(&threads[i], NULL, test, (void *)&(i));
}
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
//std::cerr << "duration = " << duration.count() << "us" << std::endl;
double time_used = duration.count() / 1e3;
std::ofstream f_time("time.out");
f_time << std::fixed << std::setprecision(3) << time_used << std::endl;
f_time.close();
for (int i = 0; i < k; i++)
{
for (int j = 0; j < op_num[i]; j++)
{
ans[data[i][j].time - 1] = data[i][j].ans;
}
}
ofstream fout;
fout.open("result.out");
for (int i = 0; i < 30000000; i++)
{
if (ans[i] >= 0)
fout << ans[i] << endl;
}
fout.close();
delete[] data;
delete[] threads;
delete[] op_num;
//pthread_exit(NULL);
}
My code can compile, but when running it shows segmentation fault and can only generate time.out no result.out. I've been working on it for a long time but still do not know why. Hope someone can help me.
Below is block.h
#include <algorithm>
#include <chrono>
#include <cmath>
#include <ctime>
#include <fstream>
#include <iostream>
#include <numeric>
#include <string>
#include <vector>
#include "Headers/MurmurHash3.h"
#include "xxHash/xxhash.c"
#define M_LN2 0.69314718055994530942
using namespace std;
typedef std::vector<bool> bit_vector;
class Operation
{
public:
int type; // 1: insert, 2: query
char key[17];
int time;
int ans;
};
int str_len = 16;
int cache_size = 64;
int block_size = 512;
int key_num = 10000000;
int slot_num = 1 << 27;
int hash_num = int((double)slot_num / key_num * M_LN2);
int block_num = (slot_num + block_size - 1) / block_size;
class bloom_filter
{
uint32_t size; // Probable Number of elements in universe
double fpr; // False positive rate
int m; // optimal size of bloom filter
int k; // Number of hash functions
bit_vector bloom;
public:
int get_size() { return size; }
double get_fpr() { return fpr; }
bloom_filter(int n, double fpr)
{
this->size = n;
this->fpr = fpr;
this->m = ceil(
-((n * log(fpr)) /
pow(log(2), 2.0))); // Natural logarithm m = −n ln p/(ln 2)2
// cout << m<< "\n";
this->k = ceil(
(m / n) * log(2)); // Calculate k k = (m/n) ln 2 2-k ≈ 0.6185 m/n
// cout << k;
bloom.resize(m, false);
}
void insert(string S)
{
uint32_t *p = new uint32_t(1); // For storing Hash Vaue
const void *str = S.c_str(); // Convert string to C string to use as a
// parameter for constant void
int index;
// cout<<S.length()<<"\t"<<sizeof(str)<<"\n";
// cout<<S<<"\n";
for (int i = 0; i < k; i++)
{
// MurmurHash3_x64_128();
MurmurHash3_x86_32(str, S.length(), i + 1,
p); // String, String size
index = *p % m;
// cout<<*p<<"\t"<<index<<"\t";
bloom[index] = true;
}
// cout<<"\n";
// print();
}
/*void print()
{
for (int i = 0; i < bloom.size(); i++)
{
cout << bloom.at(i);
}
}*/
char query(string S)
{
uint32_t *p = new uint32_t(1); // For storing Hash Vaue
const void *str = S.c_str(); // Convert string to C string to use as a
// parameter for constant void
int index;
// cout << S.length() << "\t" << sizeof(str) << "\n";
// cout<<S<<"\n";
for (int i = 0; i < k; i++)
{
// MurmurHash3_x64_128();
MurmurHash3_x86_32(str, S.length(), i + 1,
p); // String, String size
index = *p % m;
// cout<<*p<<"\t"<<index<<"\t";
if (bloom[index] == false)
return 'N';
}
return 'Y';
}
};
class block_bloom_filter
{
int size; // Probable Number of elements in universe
double fpr; // False positive rate
int m; // optimal size of bloom filter
int k; // Number of hash functions
int s; // Number of bloom filters
bit_vector block_bloom;
int cache_line_size;
public:
int get_size() { return size; }
double get_fpr() { return fpr; }
block_bloom_filter(int n, double fpr)
{
this->size = n;
this->fpr = fpr;
this->m = ceil(
-((n * log(fpr)) /
pow(log(2), 2.0))); // Natural logarithm m = −n ln p/(ln 2)2
// cout << m << "\n";
this->k = ceil(
(m / n) * log(2)); // Calculate k k = (m/n) ln 2 2-k ≈ 0.6185 m/n
// cout << k<<"\n";
this->cache_line_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) * 8;
this->s =
ceil((double)m / cache_line_size); // Total number of Bloom Filters
// cout<<s<<"s valye\n";
block_bloom.resize(cache_line_size * s, false);
}
/*void insert(Operation &S)
{
int block_number;
int first_index, last_index;
int index;
uint32_t *p = new uint32_t(1); // For storing Hash Value
const void *str = S.key.c_str(); // Convert string to C string to use as a
// parameter for constant void
MurmurHash3_x86_32(str, sizeof(str), 1,
p); // String, String size//Find out block number
// if(s!=0)
block_number = *p % s;
first_index = block_number * cache_line_size;
for (int i = 1; i < k; i++)
{
// MurmurHash3_x64_128();
MurmurHash3_x86_32(str, S.key.length(), i + 1,
p); // String, String size
// cout<<*p<<"\n";
// cout<<"div="<<div << "\n";
index = (*p) % cache_line_size;
// cout<<index<<"\t";
// if(index>m) cout<<"\n"<<index<<"\tError detected\n";
// cout<<"\n"<<index<<"a\t\n";
// cout<<"\n"<<first_index<<"a\t\n";
// cout<<(index+first_index)<<"a\t\n";
block_bloom[index + first_index] = true;
}
// cout<<"\n";
// print();
}*/
XXH64_hash_t GetHash(const char *str)
{
return XXH3_64bits_withSeed(str, 16, /* Seed */ 123976235672331983ll);
}
void insert(Operation &s)
{
XXH64_hash_t hash = GetHash(s.key);
XXH64_hash_t hash1 = hash % m;
XXH64_hash_t hash2 = (hash / m) % m;
for (int i = 0; i < k; i++)
{
int pos = (hash1 + i * hash2) % m;
block_bloom[pos] = 1;
}
}
void query(Operation &s)
{
XXH64_hash_t hash = GetHash(s.key);
XXH64_hash_t hash1 = hash % m;
XXH64_hash_t hash2 = (hash / m) % m;
for (int i = 0; i < k; i++)
{
int pos = (hash1 + i * hash2) % m;
if (!block_bloom[pos])
{
s.ans = 0;
return;
}
}
s.ans = 1;
return;
}
};
for (int i = 0; i < k; i++)
{
pthread_create(&threads[i], NULL, test, (void *)&(i));
The third parameter to pthread_create(), the thread function's parameter, is a pointer to the loop variable. The thread function reads it, as follows:
void *test(void *arg)
{
int thread_id = *((int *)arg);
There are no guarantees whatsoever that this gets executed by the new execution thread before the parent execution thread increments i. When it comes to multiple execution threads, neither POSIX nor the C++ library gives you any guarantees as to the relative execution order of multiple threads.
All that pthread_create() guarantees you is that at some point in time later, which can before before or after pthread_create() returns, the new execution thread pops into existence and begins executing the thread function.
And it may very well be that one or more (if not all) execution threads finally begin executing, for real, after the for loop terminates and i gets destroyed. At which pointL when they do start executing, they will discover a pointer to a destroyed variable as their argument, and dereferencing it becomes undefined behavior.
Or, some of those execution threads get their gear running, at some point after they get created. By this time i's been incremented a couple of times already. So they both read the *(int *)arg, whose value is now -- who knows? And, just to make things interesting, both execution threads do this at the same time, and read the same value. At this point, the end result is already going to be garbage. It is clear that the intent here is for each execution thread getting a unique value for its parameter, but this very unlikely to happen here. There's nothing in the shown code that ensures that each execution threads actually gets its own unique thread_id.
Additionally, the original parent execution thread seems to assume that all the execution threads will all finish their job before the parent execution thread reads their results, and writes them out to a file.
Unfortunately, there's no code in the parent execution thread that appears to actually wait for all execution threads to finish. As soon as they're all started, it takes it on faith that they complete instantly, and it reads the partial results, and writes it out to a file:
auto stop = std::chrono::high_resolution_clock::now();
Well, the bad news here is that there's nothing that actually waits for all execution threads to actually stop, at this point. They're still running here. Even if the program manages to avoid crashing, the output results will be incomplete, and mostly junk.
ans[data[i][j].time - 1]
It appears that the value of .time here was originally read from the input file. There does not appear to be any bounds checking here. It's possible for this vector/array access to be out of bounds, resulting in an undefined behavior and a likely crash.
Also, another problem with the shown code: There are plenty of calls to new, but only some of those get deleted, resulting in multiple memory leaks. Inspecting the shown code, there is no clear reason to new anything, in the first place.
In conclusion, there are multiple problems with the shown code that result in undefined behavior, and any of them will be the reason for the observed crash. The shown approach is very much error-prone, and will require much more substantial work, and proper multi-threading support, and inter-thread sequencing, in order to get the sequence of all events happen in the correct order, across all the execution threads.
Related
I want to write a method in C++ which creates an array of monotonically increasing values. It has the inputs of int begin, int end, int interval.
In this example; method should return the array of [0,1,2,3,4,5,6,7,8,9,10]. When I print the results it should print out the first two indexes and get 0 and 1. However, when I print it, it gives 0 for the first one and 9829656 for the second one.
When I only print one index it is always correct, but when I print more than one index, every value except for the first printed one gives a different result. I think the other results are related to memory address since I used pointers.
#include <iostream>
using namespace std;
int* getIntervalArray(int begin, int end, int interval){
int len = (end - begin) / interval + 1;
int result[11] = {};
for (int i = 0; i <= len - 1; i++) {
result[i] = begin + interval * i;
}
return result;
}
int main(){
int begin = 0;
int end = 10;
int interval = 1;
int* newResult = getIntervalArray(begin, end, interval);
cout << newResult[0] << endl;
cout << newResult[1] << endl;
return 0;
}
You are returning a pointer to a local variable. You can instead return a std::vector by value as shown below:
#include <iostream>
#include <vector>
//return a vector by value
std::vector<int> getIntervalArray(int begin, int end, int interval){
int len = (end - begin) / interval + 1;
std::vector<int> result(len); //create a vector of size len
for (int i = 0; i <= len - 1; i++) {
result.at(i) = begin + interval * i;
}
return result;
}
int main(){
int begin = 0;
int end = 10;
int interval = 1;
std::vector<int> newResult = getIntervalArray(begin, end, interval);
//print out elements of returned vector
for(int i = 0; i < newResult.size(); ++i)
{
std::cout << newResult.at(i) << std::endl;
}
return 0;
}
The output of the above program can be seen here.
A possible solution dynamically allocating the local array, and returning it via a smart pointer:
#include <array>
#include <iostream>
#include <memory> // make_unique
auto getIntervalArray(int begin, int end, int interval)
{
int len = (end - begin) / interval + 1;
auto result{ std::make_unique<std::array<int, 11>>() };
for (int i = 0; i <= len - 1; i++) {
(*result)[i] = begin + interval * i;
}
return result;
}
int main()
{
int begin = 0;
int end = 10;
int interval = 1;
auto newResult{ getIntervalArray(begin, end, interval) };
std::cout << (*newResult)[0] << std::endl;
std::cout << (*newResult)[1] << std::endl;
std::cout << (*newResult)[2] << std::endl;
return 0;
}
Demo
Set the array variable in your function as static. This is because C++ does not support returning the address of a local variable.
static int result[11];
try this. also add deletion of the newResult
#include <iostream>
using namespace std;
int* getIntervalArray(int begin, int end, int interval){
int len = (end - begin) / interval + 1;
int* result = new int[len];
int lastValue = begin;
for (int i = 0; i <= len - 1; i++) {
result[i] = lastValue;
lastValue += interval;
}
return result;
}
int main(){
int begin = 0;
int end = 10;
int interval = 1;
int* newResult = getIntervalArray(begin, end, interval);
cout << newResult[0] << endl;
cout << newResult[1] << endl;
// add delete here.
return 0;
}
I'm trying to create a program that solves the problem of dining philosophers using posix threads. However, I got stuck at the very beginning, since the output of std :: cout << id + 1 << "PHILOSOPHER: thinking" << std :: endl; ++ i; is incorrect and id takes too large values. Please point out my mistake.
pthread_mutex_t mutexSpoon[PHILOSOPHERS];
pthread_t createThread(int number){
pthread_t id;
int rc = pthread_create(&id, NULL, philFunc, &number);
if(rc){
abort();
}
return id;
}
void *philFunc(void *arg){
srand(time(0));
int id = *(int*)arg;
int leftSpoon = (id>0) ? id-1 : PHILOSOPHERS;
int rightSpoon = id;
int temp;
int i = 0;
while(i < 10){
usleep((200 - 50) * ( (double)rand() / RAND_MAX ) + 50);
std::cout << id+1 << " PHILOSOPHER: thinking" << std::endl; ++i;
}
return nullptr;
}
main.cpp
using namespace std;
extern pthread_mutex_t mutexSpoon[PHILOSOPHERS];
int main(){
setlocale(LC_ALL, "rus");
for(int i = 0; i < PHILOSOPHERS; ++i)
pthread_mutex_init(&mutexSpoon[i], NULL);
vector<pthread_t> vecID(PHILOSOPHERS);
for(int i = 0; i < PHILOSOPHERS; ++i)
vecID[i] = createThread(i);
for(int i = 0; i < PHILOSOPHERS; ++i)
pthread_join(vecID[i], NULL);
for(int i = 0; i < PHILOSOPHERS; ++i)
pthread_mutex_destroy(&mutexSpoon[i]);
return 0;
}
thread function uses an address for argument, which you pass as an address to a local variable of function createThread - number. The life span of argument should be not shorter than thread, so exactly same as the mutex. Using your snippets as base, I created an example which works around the issue:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <pthread.h>
#include <unistd.h>
void *philFunc(void *arg);
#define PHILOSOPHERS 10
struct Philosopher {
pthread_mutex_t mutexSpoon;
pthread_t id;
int no;
};
Philosopher philosophers[PHILOSOPHERS] = {};
pthread_t createThread(int& number){
pthread_t id;
int rc = pthread_create(&id, NULL, philFunc, &number);
if(rc){
abort();
}
return id;
}
void *philFunc(void *arg){
srand(time(0));
int id = *(int*)arg;
int leftSpoon = (id>0) ? id-1 : PHILOSOPHERS;
int rightSpoon = id;
int temp;
int i = 0;
while(i < 10){
usleep((200 - 50) * ( (double)rand() / RAND_MAX ) + 50);
std::cout << id+1 << " PHILOSOPHER: thinking" << std::endl; ++i;
}
return nullptr;
}
extern pthread_mutex_t mutexSpoon[PHILOSOPHERS];
int main(){
setlocale(LC_ALL, "rus");
for(int i = 0; i < PHILOSOPHERS; ++i) {
pthread_mutex_init(&philosophers[i].mutexSpoon, NULL);
philosophers[i].no = i;
philosophers[i].id = createThread(philosophers[i].no);
}
for(int i = 0; i < PHILOSOPHERS; ++i)
pthread_join(philosophers[i].id, NULL);
for(int i = 0; i < PHILOSOPHERS; ++i)
pthread_mutex_destroy(&philosophers[i].mutexSpoon);
return 0;
}
As you see, there is now own structure Philosopher for each thread, storing its data as it should be. While philosophers here is an array, it can be any other container as long as its elements live long enough and aren't changing their addresses (requirement for some implementations of the pthread mutex).
Note that createThread(int& number) now takes its argument by reference, so the expression &number would get address of the actual object's location, not of local variable.
This code can be simpler, if using C++ thread support and std::future.
#include <iostream>
#include <chrono>
#include <random>
using namespace std;
class MyTimer
{
private:
std::chrono::time_point<std::chrono::steady_clock> starter;
std::chrono::time_point<std::chrono::steady_clock> ender;
public:
void startCounter() {
starter = std::chrono::steady_clock::now();
}
long long getCounter() {
ender = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::microseconds>(ender - starter).count();
}
};
int findBestKey(int keys[4], int values[4])
{
int index = 0;
for (int i = 1; i <= 3; i++)
if (keys[index] > keys[i])
index = i;
return values[index];
}
int findBestKeyPro(int keys[4], int values[4])
{
int index = keys[0] > keys[1];
if (keys[index] > keys[2]) index = 2;
if (keys[index] > keys[3]) return values[3];
else return values[index];
}
int findBestKeyProMax(int keys[4], int values[4])
{
// fill your implementation here. Not necessary to read the parts below
return 0;
}
void benchMethod(int (*findBestKeyFunc)(int keys[4], int values[4]), int n, int* keys, int* values, int& res, double& totalTime)
{
MyTimer timer;
timer.startCounter();
// In my actual problems, values of arrays "keys" are completely unrelated. They are not the same continuous values in memory. The line below is just an example for benchmark purposes
for (int i = 0; i < n - 4; i+=4)
res += findBestKeyFunc(&keys[i], &values[i]);
totalTime += timer.getCounter();
/*
it is possible to calculate 4 arrays "keys","values", then process them all at once.
for (int i=0; i<n-4; i+=16)
{
keys[4][4] = ...; values[4][4] = ...;
res += find4BestKeyAtOnce(&keys, &values);
}
*/
}
double totalTimeNormal = 0, totalTimePro = 0, totalTimeProMax = 0;
void benching(int& res1, int& res2, int& res3)
{
const int n = 10000000;
int* keys1 = new int[n], * values1 = new int[n];
int* keys2 = new int[n], * values2 = new int[n];
MyTimer timer;
double tmp;
for (int i = 0; i < n; i++) {
keys1[i] = rand() % 100; // need 2 arrays to prevent caching
keys2[i] = rand() % 100; // this should be % (256*256)
values1[i] = rand() % 100; // and % 256
values2[i] = rand() % 100; // but I use % 100 so that in this example it doesn't overflow int32
}
// the size of keys2/values2 is big enough to flush out keys1/values1 from cache completely.
// so order of execution doesn't affect performance here
benchMethod(&findBestKey, n, keys1, values1, res1, totalTimeNormal);
benchMethod(&findBestKey, n, keys2, values2, res1, totalTimeNormal);
benchMethod(&findBestKeyPro, n, keys1, values1, res2, totalTimePro);
benchMethod(&findBestKeyPro, n, keys2, values2, res2, totalTimePro);
benchMethod(&findBestKeyProMax, n, keys1, values1, res2, totalTimeProMax);
benchMethod(&findBestKeyProMax, n, keys2, values2, res2, totalTimeProMax);
delete[] keys1;
delete[] keys2;
delete[] values1;
delete[] values2;
}
void testIf()
{
int res1 = 0, res2 = 0, res3 = 0;
for (int t = 1; t <= 100; t++) {
benching(res1, res2, res3);
res1 %= 100;
res2 %= 100;
res3 %= 100;
cout << "Lap " << t << "\n";
cout << "time normal = " << totalTimeNormal/1000 << " ms\n";
cout << "time pro = " << totalTimePro/1000 << " ms\n";
cout << "time pro max = " << totalTimeProMax/1000 << " ms\n";
cout << "\n";
}
cout << "**********************\n" << res1 << " " << res2 << "\n";
}
int main()
{
testIf();
return 0;
}
There are two arrays, keys and values, both completely random. This function returns the value that has the minimum key. So: index = indexOfMin(keys); return values[index]; See function findBestKey. I need to fill in findBestKeyProMax
findBestKeyPro is around 30-35% faster than findBestKey, on my computer and on here: https://www.onlinegdb.com/online_c++_compiler . Compiler option is -std=c++14 -O2 Update: I get ~~5-10% more performance just by changing to -O3
Is there anyway I can make this faster? Every nanosecond matters, since this function is called ~~10^6-10^7 times (once for each pixel); saving 1 ns per call would translate to 1ms less, which is the difference between 200fps and 250fps.
Edit: no multi-threading or GPU. It's already done (each thread performs findBestKey on distinct keys/values arrays), so I want to improve this function directly. Maybe something like SIMD for CPU? Or branchless function.
Also the functions findBest... are what matters, function benchMethod() is just for benchmarking.
Edit 2: target architecture is CPUs with AVX256 capability, mainly Intel Skylake or AMD Zen 2.
I've to create a prime checker using semaphores. The code executes till the "Finding Primes from" part and after that crashes saying "Segmentation Fault (Core Dumped)". After searching about this I understand that it happens when the program tries to access a part of memory that isn't available; but I don't understand it in my code. Please do a take a look and thank you!
#include <QThread>
#include <QSemaphore>
#include <QMutex>
#include <iostream>
#include <stdlib.h>
#include <cmath>
#include <vector>
using namespace std;
#define TOTALSPACE 50
vector<int> buffer(TOTALSPACE);
QSemaphore space(TOTALSPACE), avail;
QMutex l;
int prime_from, prime_to, num_threads;
int total = 0, cnumber = 0;
int in = 0, out = 0;
bool b = false;
//-----Generator------
class Generator : public QThread
{
private:
int strt;
int end;
public:
Generator(int a, int b)
{
strt = a;
end = b;
cnumber = strt;
}
void run()
{
while (cnumber < end)
{
space.acquire();
cnumber++;
buffer[in] = cnumber;
in = (in + 1) % TOTALSPACE;
avail.release();
}
b = true;
for (int i = 0; i < num_threads; i++)
{
space.acquire();
buffer[in] = -1;
in = (in + 1) % TOTALSPACE;
avail.release();
}
}
};
//-----------Checker----------
class Checker : public QThread
{
private:
int number;
public:
Checker() {}
void run();
};
void Checker::run()
{
while (1)
{
avail.acquire();
l.lock();
number = buffer[out];
if (number == -1)
{
l.unlock();
break;
}
bool isPrime = false;
for (int i = 2; i <= sqrt(number); i++)
{
if (number%i == 0)
{
isPrime = true;
break;
}
}
out = (out + 1) % TOTALSPACE;
if (isPrime == false)
{
total++;
}
l.unlock();
space.release();
}
}
//-------------Main---------
int main(int argc, char *argv[])
{
num_threads = atoi(argv[1]);
prime_from = atoi(argv[2]);
prime_to = atoi(argv[3]);
cout << " Number of Threads = " << num_threads << endl;
cout << " Primes checking from " << prime_from << " to " << prime_to << endl;
Generator gen(prime_from, prime_to);
gen.start();
Checker* thr[num_threads];
for (int i = 1; i < num_threads; i++)
{
thr[i] = new Checker();
thr[i]->start();
}
gen.wait();
for (int i = 0; i < num_threads; i++)
{
thr[i]->wait();
}
cout << "Total Primes: " << total << endl;
return 0;
}
There's a couple of things that could cause this. For one, you never check whether there's enough parameters supplied or not (argc>3). So you could pass invalid pointers to atoi
But far more likely is that you did not initialize thr[0] because you start your initialization loop with for (int i = 1; but you access thr[0] in the loop for synchronization because you start it with or (int i = 0;.
In addition it is noteworthy that you are using Variable Length Arrays when you do Checker* thr[num_threads]; because num_threads is not a compile-time constant. That feature is not part of the C++ standard at this time (not in C++14). So, if you want to make your program portable you can do Checker** thr = new Checker*[num_threads]; and delete [] thr; at the end if you want to be diligent (and not use smart pointers).
Hey guys I'm working on some sorts and am trying to implement a bubble sort, a merge sort, and a shell sort. I use an outdated technique but I was wondering if you guys could let me know why I keep getting the following error:
First-chance exception at 0x01135EF7 in sortApplication2.exe: 0xC00000FD: Stack overflow (parameters: 0x00000000, 0x00542000).
Unhandled exception at 0x01135EF7 in sortApplication2.exe: 0xC00000FD: Stack overflow (parameters: 0x00000000, 0x00542000).
I am using Visual Studio 2012 if that plays any part. My code is in three different files so I'll post each separately.
My header file:
#pragma once
class sort
{
public:
sort();
void random1(int array[]);
void random2(int array[]);
void random3(int array[]);
void bubbleSort(int array[], int length);
/*void merge(int *input, int p, int r);
void merge_sort(int *input, int p, int r);*/
void shellSort(int array[], int length);
};
My class implementation file:
#include "sort.h"
#include <time.h>
#include <iostream>
using namespace std;
sort::sort()
{}
void sort::random1(int array[])
{
// Seed the random-number generator with current time so that
// the numbers will be different every time the program runs.
for(int i = 0; i < 25; i++)
{
srand ((unsigned) time(NULL));
int n = rand(); //generates a random number
array[i] = n; //places it into the array
}
}
void sort::random2(int array[])
{
// Seed the random-number generator with current time so that
// the numbers will be different every time the program runs.
for(int i = 0; i < 10000; i++)
{
srand ((unsigned) time(NULL));
int n = rand(); //generates a random number
array[i] = n; //places it into the array
}
}
void sort::random3(int array[])
{
// Seed the random-number generator with current time so that
// the numbers will be different every time the program runs.
for(int i = 0; i < 100000; i++)
{
srand ((unsigned) time(NULL));
int n = rand(); //generates a random number
array[i] = n; //places it into the array
}
}
void sort::bubbleSort(int array[], int length)
{
//Bubble sort function
int i,j;
for(i = 0; i < 10; i++)
{
for(j = 0; j < i; j++)
{
if(array[i] > array[j])
{
int temp = array[i]; //swap
array[i] = array[j];
array[j] = temp;
}
}
}
}
/*void sort::merge(int* input, int p, int r) //the merge algorithm of the merge sort
{
int mid = (p + r) / 2;
int i1 = 0;
int i2 = p;
int i3 = mid + 1;
// Temp array
int x = r -p + 1;
int *temp;
temp = new int [x];
// Merge in sorted form the 2 arrays
while ( i2 <= mid && i3 <= r )
if ( input[i2] < input[i3] )
temp[i1++] = input[i2++];
else
temp[i1++] = input[i3++];
// Merge the remaining elements in left array
while ( i2 <= mid )
temp[i1++] = input[i2++];
// Merge the remaining elements in right array
while ( i3 <= r )
temp[i1++] = input[i3++];
// Move from temp array to master array
for ( int i = p; i <= r; i++ )
input[i] = temp[i-p];
}
void sort::merge_sort(int *input, int p, int r) //the merge sort algorithm
{
if ( p < r ) //When p and r are equal the recursion stops and the arrays are then passed to the merge function.
{
int mid = (p + r) / 2;
merge_sort(input, p, mid); //recursively calling the sort function in order to break the arrays down as far as possible
merge_sort(input, mid + 1, r);//recursively calling the sort function in order to break the arrays down as far as possible
merge(input, p, r); //merge function realigns the smaller arrays into bigger arrays until they are all one array again
}
}*/
void sort::shellSort(int array[], int length) //Shell sort algorithm
{
int gap, i, j, temp;
for( gap = length / 2; gap > 0; gap /= 2) //gap is the number of variables to skip when doing the comparisons
{
for( i = gap; i < length; i++) //This for loop sets the variable to use as the gap for the comparisons
{
for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap)
{
temp = array[j]; //the array variables are swapped
array[j] = array[j + gap];
array[j + gap] = temp;
}
}
}
}
And my driver file:
#include "sort.h"
#include <iostream>
using namespace std;
int main()
{
int bubbleArray1[25]; //these are the arrays to be sorted. three for each sort. each has a length of 25, 10000, or 100000.
int bubbleArray2[10000];
int bubbleArray3[100000];
int mergeArray1[25];
int mergeArray2[10000];
int mergeArray3[100000];
int shellArray1[25];
int shellArray2[10000];
int shellArray3[100000];
sort Sorts;
Sorts.random1(bubbleArray1);
Sorts.random1(mergeArray1);
Sorts.random1(shellArray1);
Sorts.random2(bubbleArray2);
Sorts.random2(mergeArray2);
Sorts.random2(shellArray2);
Sorts.random3(bubbleArray3);
Sorts.random3(mergeArray3);
Sorts.random3(shellArray3);
cout << "BubbleSort1 is now being sorted.\n";
Sorts.bubbleSort(bubbleArray1, 25);
cout << "BubbleSort2 is now being sorted.\n";
Sorts.bubbleSort(bubbleArray2, 10000);
cout << "BubbleSort3 is now being sorted.\n";
Sorts.bubbleSort(bubbleArray3, 100000);
cout << "End bubble sorts.\n";
/*cout << "MergeSort1 is now being sorted.\n";
Sorts.merge_sort(mergeArray1, 0, 25);
cout << "MergeSort2 is now being sorted.\n";
Sorts.merge_sort(mergeArray2, 0, 10000);
cout << "MergeSort3 is now being sorted.\n";
Sorts.merge_sort(mergeArray3, 0, 100000);
cout << "End merge sorts.\n";*/
cout << "ShellSort1 is now being sorted.\n";
Sorts.shellSort(shellArray1, 25);
cout << "ShellSort1 is now being sorted.\n";
Sorts.shellSort(shellArray2, 10000);
cout << "ShellSort1 is now being sorted.\n";
Sorts.shellSort(shellArray3, 100000);
cout << "End shell sorts.\n";
cout << "Array\tElements\n";
cout << "BubbleSort1\t";
for(int i = 0; i < 25; i++)
{
cout << bubbleArray1[i] << " ";
}
cout << "\nMergeArray1\t";
for(int i = 0; i < 25; i++)
{
cout << mergeArray1[i] << " ";
}
cout << "\nShellArray1\t";
for(int i = 0; i < 25; i++)
{
cout << shellArray1[i] << " ";
}
return 0;
}
I know it's a lot of code. And there are probably many ways I could make the code better.
I would just like to know what's causing the error up above since I can't find it using my compiler.
You are allocating too much memory on the stack. Variables with 'automatic' storage class go on the stack. Allocate heap instead.
So, instead of:
int shellArray3[100000];
Do:
int* shellArray3 = new int[100000];
Or better yet, use std::vector.
If you don't want to use heap memory, you could also use the static storage class for something like this. To do that:
static int shellArray3[100000];
That will allocate one instance of the variable for the whole program rather than allocating a copy for each function entry on the stack.