I wanted to learn how threads work, and I tried to make a program, which would use 2 threads, to copy a picture (just to test my newly acquired threading skills) . But I bumped into an error, probably because my interval (created by the interval function) is only working ( I believe) with one dimensional arrays.How can I change my program , to correctly create intervals , which work on 2 dimensional arrays, such as pictures ?
#include <iostream>
#include <vector>
#include <time.h>
#include <thread>
#include <mutex>
#include <png++/png.hpp>
std::mutex my_mutex;
std::vector<int> interval(int max, int n_threads)
{
std::vector<int> intervallum;
int ugras = max / n_threads;
int maradek = max % n_threads;
int n1 = 0;
int n2;
intervallum.push_back(n1);
for (int i = 0; i < n_threads; i++)
{
n2 = n1 + ugras;
if (i == n_threads - 1)
n2 += maradek;
intervallum.push_back(n2);
n1 = n2;
}
return intervallum;
}
void create_image(png::image<png::rgb_pixel> image, png::image<png::rgb_pixel> new_image, int start, int end)
{
std::lock_guard<std::mutex> lock(my_mutex);
for (int i = start; i < end; i++)
for (int j = start; j < end; j++)
{
new_image[i][j].red = image[i][j].red;
new_image[i][j].blue = image[i][j].blue;
new_image[i][j].green = image[i][j].green;
}
}
int main()
{
png::image<png::rgb_pixel> png_image("mandel.png");
int image_size = png_image.get_width() * png_image.get_height();
png::image<png::rgb_pixel> new_image(png_image.get_width(), png_image.get_height());
time_t start, end;
time(&start);
int size = 2;
std::vector<std::thread> threads;
std::vector<int> stuff_interval = interval(image_size, size);
for (int i = 0; i < size-1; i++)
threads.push_back(std::thread(create_image, std::ref(png_image), std::ref(new_image), stuff_interval[i], stuff_interval[i + 1]));
for (auto& i : threads)
i.join();
create_image(png_image,new_image,stuff_interval[size-2],stuff_interval[size-1]);
new_image.write("test.png");
time(&end);
std::cout << (start - end) << std::endl;
return 0;
}
Okay , I found a way around it (this way I am not getting segmentation error, but it does not copy the image correctly, the new image is fully black, here is the code :
EDIT : seems like, I was passing wrong the pictures, that is the reason why the picture was black.
#include <iostream>
#include <vector>
#include <time.h>
#include <thread>
#include <mutex>
#include <png++/png.hpp>
std::mutex my_mutex;
std::vector<int> interval(int max, int n_threads)
{
std::vector<int> intervallum;
int ugras = max / n_threads;
int maradek = max % n_threads;
int n1 = 0;
int n2;
intervallum.push_back(n1);
for (int i = 0; i < n_threads; i++)
{
n2 = n1 + ugras;
if (i == n_threads - 1)
n2 += maradek;
intervallum.push_back(n2);
n1 = n2;
}
return intervallum;
}
void create_image(png::image<png::rgb_pixel>& image, png::image<png::rgb_pixel>& new_image, int start, int end)
{
std::lock_guard<std::mutex> lock(my_mutex);
for (int i = start; i < end; i++)
for (int j = 0; j < image.get_height(); j++)
{
new_image[i][j].red = image[i][j].red;
new_image[i][j].blue = image[i][j].blue;
new_image[i][j].green = image[i][j].green;
}
}
int main()
{
png::image<png::rgb_pixel> png_image("mandel.png");
int image_size = png_image.get_width() * png_image.get_height();
png::image<png::rgb_pixel> new_image(png_image.get_width(), png_image.get_height());
time_t start, end;
time(&start);
int size = 2;
std::vector<std::thread> threads;
std::vector<int> stuff_interval = interval(png_image.get_width(), size);
new_image.write("test2.png");
for (int i = 0; i < size - 1; i++)
threads.push_back(std::thread(create_image, std::ref(png_image), std::ref(new_image), stuff_interval[i], stuff_interval[i + 1]));
for (auto &i : threads)
i.join();
create_image(std::ref(png_image), std::ref(new_image), stuff_interval[size - 1], stuff_interval[size]);
new_image.write("test.png");
time(&end);
std::cout << (start - end) << std::endl;
return 0;
}
Related
I'd like to find a better algorithm to find connected clusters.
For example, if I input:
(8, 6),
(1, 8),
(3, 5)
, then there are two connected clusters: <1,6,8> and <3,5>.
I tried to do that using Depth First Search, but it spent too much time (several days) when the inputs are very very substantial.
By the way, I tried to use igraph library; it was faster, but memory leak happened, my computer got breakdown.
My code (DFS) is below.
#ifndef GRAPH_I_H
#define GRAPH_I_H
#include <iostream>
#include <ctime>
#include <cmath>
#include <queue>
#include <mechsys/linalg/matvec.h>
using namespace std;
class Graph_i
{
public:
int NumOfFractures;
Array<Array<int>> G;
Array<int> Visited;
public:
Graph_i(const int NumOfFractures_1, const Array<int> Connections);
void DFS(int V, Array<int> &B);
void CreateGraph_i(Array<Array<int>> &S);
};
inline Graph_i::Graph_i(const int NumOfFractures_1, const Array<int> Connections)
{
NumOfFractures = NumOfFractures_1;
G.resize(NumOfFractures);
for (int i = 0; i < NumOfFractures; ++i)
G[i].resize(NumOfFractures);
for (int i = 0; i < NumOfFractures; ++i)
{
for (int j = 0; j < NumOfFractures; ++j)
G[i][j] = 0;
}
for (int i = 0; i < Connections.Size() / 2; ++i)
{
G[Connections[2 * i]][Connections[2 * i + 1]] = 1;
G[Connections[2 * i + 1]][Connections[2 * i]] = 1;
}
Visited.resize(NumOfFractures);
for (int i = 0; i < NumOfFractures; ++i)
{
Visited[i] = 0;
}
}
inline void Graph_i::DFS(int V, Array<int> &B)
{
Visited[V] = 1;
B.Push(V);
for (int i = 0; i < NumOfFractures; ++i)
{
if (Visited[i] == 0 && G[V][i] == 1)
DFS(i, B);
}
}
inline void Graph_i::CreateGraph_i(Array<Array<int>> &S)
{
if (S.Size() != 0)
{
std::cout << "Error! ListOfClusters should be empty array!\n";
exit(0);
}
for (int i = 0; i < NumOfFractures; ++i)
{
if (Visited[i] == 0)
{
Array<int> A;
DFS(i, A);
S.Push(A);
}
}
}
#endif
Main function (this is just one time loop; actually, in my code, there are many loops; and I have used OpenMP):
#include <Graph_i.h>
int main()
{
Array<int> Connections; //this is the input, containing pairs, e.g., 1,2,1,3,5,6; so, <1,2,3> is a connected cluster, <5,6> is also a cluster; so, I need algorithm to identify them
//size of this array can be very very large
Array< Array<int> > Listofclusters;// this two order array is used to recode connected clusters
Graph_i G(Connections.Size(), Connections);
G.CreateGraph_i(Listofclusters);
return 0;
}
I need to create a program in which random numbers between 1 and 100 are placed in each dimension of a 3D array. The arrays are of varying sizes, and thus far have only encountered crashes upon execution. Tried on a smaller scale with a 1D array and got it to work fine. Cant seem to translate on larger scale. My code so far...
int const STOCK_AMOUNT = 1000, DAY_AMOUNT = 366, TIME_AMOUNT = 480;
int randomGenerator();
void randomInsert(int array0[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT]);
int main()
{
int cube[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT];
srand((unsigned)time(0));
randomInsert(cube);
return 0;
}
void randomInsert(int array0[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT])
{
for (int count1 = 0; count1 < DAY_AMOUNT; count1++)
{
for (int count2 = 0; count2 < TIME_AMOUNT; count2++)
{
for (int count3 = 0; count3 < STOCK_AMOUNT; count3++)
{
int randomGenerator();
array0[count1][count2][count3] = randomGenerator();
cout << endl;
}
}
}
}
int randomGenerator()
{
int randNum;
int lowerLimit = 1;
int upperLimit = 100;
randNum = (rand() % upperLimit) + lowerLimit;
return randNum;
}
You seem to be exceeding stack size. your array, created on the stack, holds about 175M integers, that is, about 700MB of memory. You need to setup compilation options to increase the stack size.
EDIT: moreover, please be aware that putting such huge arrays on the stack is generally considered bad practice. Ideally, use STL vectors, that is the modern way to deal with arrays.
Here’s a more complex version using the STL:
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <functional>
#include <iostream>
#include <random>
using std::cout;
using std::endl;
// The size of a type that can hold values from 1 to 100. Used for storage. (Copy to int for calculation.)
using elem_t = int_least8_t;
// Lower and upper bounds:
constexpr int lb = 1;
constexpr int ub = 100;
constexpr size_t stocks = 100, days = 300, times = 400;
using pricearray_t = elem_t[days][times][stocks];
pricearray_t& init_prices()
/* Returns a heap-allocated array that must be deleted with delete[]. */
{
// This ugly little cast is brought to us by the C++ rules for array types.
pricearray_t &to_return = *(pricearray_t*) new pricearray_t;
const std::default_random_engine::result_type seed = std::time(NULL) * CLOCKS_PER_SEC + std::clock();
std::default_random_engine generator(seed);
std::uniform_int_distribution<int_fast8_t> distribution( lb, ub );
auto x = std::bind( distribution, generator );
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k )
to_return[i][j][k] = static_cast<elem_t>(x());
return to_return;
}
int main(void)
{
const pricearray_t &prices = init_prices();
long long int sum = 0;
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k ) {
const int x = prices[i][j][k];
assert( x >= lb );
assert( x <= ub );
sum += x;
}
cout << "The mean is " << static_cast<double>(sum) / days / times / stocks << "." << endl;
delete[] &prices;
return EXIT_SUCCESS;
}
Here’s a version that uses smart pointers to manage memory automatically:
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <random>
using std::cout;
using std::endl;
// The size of a type that can hold values from 1 to 100. Used for storage. (Copy to int for calculation.)
using elem_t = int_least8_t;
// Lower and upper bounds:
constexpr int lb = 1;
constexpr int ub = 100;
constexpr size_t stocks = 100, days = 300, times = 400;
// The unique_ptr type doesn’t play nicely with arrays of known size.
using pricearray_t = elem_t[][times][stocks];
std::unique_ptr<pricearray_t> init_prices()
/* Returns a managed pointer to an array of uniformly-distributed values.
*/
{
// This smart pointer will use its move constructor to avoid copying the entire array.
std::unique_ptr<pricearray_t> to_return = std::make_unique<pricearray_t>(days);
const std::default_random_engine::result_type seed = std::time(NULL) * CLOCKS_PER_SEC + std::clock();
std::default_random_engine generator(seed);
std::uniform_int_distribution<int_fast8_t> distribution( lb, ub );
auto x = std::bind( distribution, generator );
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k )
to_return[i][j][k] = static_cast<elem_t>(x());
return to_return;
}
int main(void)
{
/* The contents of the smart pointer will be deleted automatically when it goes out of scope.
*/
const std::unique_ptr<pricearray_t> prices = init_prices();
long long int sum = 0;
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k ) {
const int x = prices[i][j][k];
assert( x >= lb );
assert( x <= ub );
sum += x;
}
cout << "The mean is " << static_cast<double>(sum) / days / times / stocks << "." << endl;
return EXIT_SUCCESS;
}
It seems the specifications for the original cube provided by the professor were clearly much too large....odd how a professor wouldnt catch that? Scaled back the specs, and now have something that works. The bit in the main is supposed to find the average of the stock price each day(50) for each stock(100).
#include<iostream>
#include<ctime>
#include <cstdlib>
#include <fstream>
using namespace std;
const int STOCK_AMOUNT = 100, DAY_AMOUNT = 50, TIME_AMOUNT = 8;
int randomGenerator();
void priceGenerator(int [STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT]);
int main()
{
ofstream outputFile;
int cube[STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT];
double total;
srand((unsigned)time(0));
priceGenerator(cube);
outputFile.open("Average_Day_Price");
for (int row = 0; row < STOCK_AMOUNT; row++)
{
total=0;
for (int col = 0; col < DAY_AMOUNT; col++)
{
for (int layer = 0; layer < TIME_AMOUNT; layer++)
{
total = cube[row][col][layer];
double average = (total / TIME_AMOUNT);
outputFile << "STOCK Id:" << (row+1) << "--" << "--" << average <<endl:
}
}
}
outputFile.close();
return 0;
}
void priceGenerator(int array0[STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT])
{
int i,y, z;
for ( i = 0; i < STOCK_AMOUNT; i++)
{
for ( y = 0; y < DAY_AMOUNT; y++)
{
for (z = 0; z < TIME_AMOUNT; z++)
{
int randNum;
int lowerLimit = 1;
int upperLimit = 100;
randNum = (rand() % upperLimit) + lowerLimit;
array0[i][y][z] = randNum;
}
}
}
}
I have declared the following:
const int NUMBER_OF_DIGITS = 16;
std::vector<int> digits(NUMBER_OF_DIGITS);
However when I open the MSVC debugger it shows the following:
This is how I added values to the vector:
for (int i = 0; i < NUMBER_OF_DIGITS; ++i) {
scanf("%d", &digits[i]);
}
Is this normal? Can I just ignore this? Or is this a problem?
Full code(the program is still not ready yet):
#include <iostream>
#include <vector>
#include "stdio.h"
const int NUMBER_OF_DIGITS = 16;
int checksum, tmp1, tmp2, tmp3, sum = 0;
std::vector<int> digits(NUMBER_OF_DIGITS);
std::vector<int> new_digits(NUMBER_OF_DIGITS);
int luhn_checksum(std::vector<int> cardnumber[NUMBER_OF_DIGITS]) {
//step 1: duouble every second number
for (int i = 1; i < NUMBER_OF_DIGITS; i += 2) {
new_digits[i] = digits[i] * 2;
if (new_digits[i] > 9) {
//if the product is larger than 9 we will add the two numbers together
//example: 9 * 2 = 18 so we will add 1 + 8 to get 9
tmp1 += new_digits[i] % 10;
new_digits[i] /= 10;
tmp1 = 0;
}
}
//step 2: sum all the values
for (int i = 0; i < NUMBER_OF_DIGITS; ++i) {
checksum += new_digits[i];
}
return checksum;
}
void get_card_numbers(void) {
for (int i = 0; i < NUMBER_OF_DIGITS; ++i) {
scanf("%d", &digits[i]);
}
}
void initialize(void) {
for (int i = 0; i < NUMBER_OF_DIGITS; ++i) {
digits.push_back(0);
new_digits.push_back(0);
}
}
int main() {
initialize();
get_card_numbers();
printf("checksum is: %d\n", luhn_checksum(&digits));
std::cout << digits.size() << std::endl;
int x; scanf("%d", &x);
return 0;
}
The constructor you're using for digits is setting the size by specifying the count. So after calling push_back you've just added another 16 to the vector. Use a different constructor that doesn't set the count.
int _tmain(int argc, _TCHAR* argv[])
{
const int NUMBER_OF_DIGITS = 16;
std::vector<int> digits(NUMBER_OF_DIGITS);
//std::vector<int> digits;
int digitsLen = digits.size();
// Here is 16
for (int i = 0; i < NUMBER_OF_DIGITS; ++i) {
digits.push_back(0);
}
int digitsLen2 = digits.size();
// Here is 32
return 0;
}
Cleaned up your code a bit:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
static const size_t NUMBER_OF_DIGITS = 16;
class cards {
public:
cards();
void read();
int luhnChecksum() const;
private:
vector<int> digits;
};
cards::cards() : digits(NUMBER_OF_DIGITS, 0)
{
}
void cards::read() {
for_each(digits.begin(), digits.end(), [](int& i) { cin >> i; });
}
int cards::luhnChecksum() const {
vector<int> newdigits(digits.begin(), digits.end());
for (size_t i=1; i<NUMBER_OF_DIGITS; i += 2) {
newdigits[i] = digits[i] * 2;
if (newdigits[i] > 9) {
int tmp1 = newdigits[i] % 10;
newdigits[i] /= 10;
newdigits[i] += tmp1;
}
}
return accumulate(newdigits.begin(), newdigits.end(), 0);
}
int main() {
cards c;
c.read();
cout << "checksum = " << c.luhnChecksum() << endl;
return 0;
}
I'm working on a Random Quick Sort program in C++, but for some reason, by program is segfaulting, and I'm a little lost as to why.
I'm pretty sure it has something to do with my hoarePartition function, getting caught in a while loop, but I'm not really sure where the problem is.
Any help on solving this problem would be very helpful!
#import <iostream>
#import <cstdlib>
#import <random>
#import <time.h>
#include <ctime>
#include <boost/timer.hpp>
void swap(int& first, int& second)
{
int temp = first;
first = second;
second = temp;
}
int hoarePartition(int* array, int leftIndex, int rightIndex)
{
int partition = array[leftIndex];
int i = leftIndex;
int j = rightIndex + 1;
while (i < j)
{
while (array[i] < partition && i <= j)
{
i = i + 1;
}
while (array[j] > partition && j > i)
{
j = j - 1;
cout << j << endl;
}
swap(array[i], array[j]);
}
swap(array[i], array[j]);
swap(array[leftIndex], array[j]);
return j;
}
void randomQuickSort(int* array, int leftIndex, int rightIndex)
{
if (leftIndex < rightIndex)
{
int q = rand() % (rightIndex - leftIndex) + leftIndex;
swap(array[leftIndex], array[q]);
int s = hoarePartition(array, leftIndex, rightIndex);
randomQuickSort(array, leftIndex, s-1);
randomQuickSort(array, s+1, rightIndex);
}
}
int main(int argc, char** argv)
{
srand(time(NULL));
int size = atoi(argv[1]);
int* array = new int[size];
for (int i = 0; i < size; ++i)
{
array[i] = (100.0 * rand()) / RAND_MAX;
}
boost::timer t;
randomQuickSort(array, 0, size);
std::cout << t.elapsed() << endl;
delete[] array;
return 0;
}
You call randomQuickSort with rightIndex=size, which is one bigger than the index of the last element in the array. Then, passing this to hoarePartition, you initialize j to rightIndex+1, and then (in the second inner while loop) access array[j].
You are accessing size+1 in your hoarePartition function. Which is 2 elements out of range for your array, resulting in a index out of range exception.
I am trying to write a parallel bubblesort function. I am running into an error when using boost::bind:
void swap(vector<int>& input, int i, int j)
{
if (input[i] > input[j])
{
int temp = input[j];
input[j] = input[i];
input[i] = temp;
}
return;
}
void parallel_bubblesort(vector<int>& input, int, int)
{
int i, j, temp;
for (i = 0; i < input.size(); i++)
{
boost::asio::io_service ioService;
boost::thread_group threadpool;
for (j = 0; j < input.size() - 1; j++)
{
ioService.post(boost::bind(&swap, boost::ref(input), 2 * j + i % 2, 2 * j + 1 + i % 2));
}
for (int t = 0; t < NUM_THREADS; t++)
{
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
threadpool.join_all();
ioService.stop();
}
return;
}
It snags on the line
ioService.post(boost::bind(&swap, boost::ref(input), 2 * j + i % 2, 2 * j + 1 + i % 2));
The error says
no matching function for call to ‘bind(<unresolved overloaded function type>, std::vector<int, std::allocator<int> >&, int, int)’
This seems weird, because none of these are overloaded at all, does anybody know what this means?
Edit: Here is the full program
#include <iostream>
#include <chrono>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <boost/thread.hpp>
#include <boost/asio/io_service.hpp>
#define NUM_THREADS 4
using namespace std;
using namespace boost;
using namespace boost::this_thread;
int check_solution(const vector<int>&);
void bubblesort(vector<int>&);
void swap1(vector<int>&, int, int);
void parallel_bubblesort(vector<int>&);
int main()
{
string line, token;
string file = "test.txt";
vector<int> unsorted_integers;
//print out filename
cout << file << endl;
ifstream myfile(file);
//open file
if(myfile.is_open())
{
//load everything into a vector
while (getline(myfile, line))
{
int temp;
std::istringstream ss(line);
std::getline(ss, token, '\n');
temp = atoi(token.c_str());
unsorted_integers.push_back(temp);
}
}
vector<int> unsorted_integers2(unsorted_integers);
//starts clock
std::chrono::high_resolution_clock::time_point start2 = std::chrono::high_resolution_clock::now();
//run the sort function and check for correctness
parallel_bubblesort(unsorted_integers2);
if(check_solution(unsorted_integers2))
{
cout << "The parallel sort solution is correct" << endl;
}
else
{
cout << "The parallel sort solution is incorrect" << endl;
}
//stops clock and prints times
std::chrono::high_resolution_clock::time_point end2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double> total_time2 = std::chrono::duration_cast<std::chrono::duration<double>>(end2 - start2);
cout << "The parallel sort function took " << total_time2.count() << " seconds." << endl;
return 0;
}
void swap1(vector<int>& input, int i, int j)
{
if (input[i] > input[j])
{
int temp = input[j];
input[j] = input[i];
input[i] = temp;
}
return;
}
void parallel_bubblesort(vector<int>& input, int, int)
{
int i, j;
for (i = 0; i < input.size(); i++)
{
boost::asio::io_service ioService;
boost::thread_group threadpool;
for (j = 0; j < input.size() - 1; j++)
{
ioService.post(boost::bind(&swap1, boost::ref(input), 2 * j + i % 2, 2 * j + 1 + i % 2));
}
for (int t = 0; t < NUM_THREADS; t++)
{
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
threadpool.join_all();
ioService.stop();
}
return;
}
int check_solution(const vector<int>& solution)
{
vector<int> correct_solution(solution);
std::sort(correct_solution.begin(), correct_solution.end());
return (solution == correct_solution);
}
You are probably doing using namespace std; somewhere, and std::swap is a thing. I suggest you simply rename your swap function to something else.