Reputation: 57
This program does takes file names from a Queue ,after user entered them, which is myQue then put them into the mainQue after that it opens those files and decrypts them if possible. If decryption is successful then it writes the decrypted data into a new file.
Main.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "Queue.h"
#include "randgen.h"
#include <thread>
#include <mutex>
using namespace std;
Queue myQue; //My structure to store the file names
Queue mainQue; //Main que for the threads
RandGen Ran; //Random Generator object
// Mutexes for certain restrictions
std::mutex mtx_blockMyQue, mtx_blockMainQue, mtx_blockPrint;
//Function for decrypt the message
void decipher(string str, int shift)
{
for (int i = 0; i < str.length(); ++i)
{
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] + shift;
}
}
}
//Function for finding the most frequent letter
char mostFrequent(string text)
{
int max = 0;
int count = 0;
char maxCharcter;
for (char q = 'a'; q <= 'z'; q++)
{
count = 0;
for (int i = 0; i<text.length(); i++)
{
if (text[i] == q)
count++;
}
if (count>max)
{
max = count;
maxCharcter = q;
}
}
return maxCharcter;
}
void sleepThr(int thrNum, int time)
{
mtx_blockPrint.lock();
this_thread::sleep_for(chrono::milliseconds(time));
cout << "Producer Thread - " << thrNum << " starts sleeping for " << time << "milliseconds" << endl;
mtx_blockPrint.unlock();
}
//What producer threads do
void producer(Queue &myQue, Queue &mainQue , int thrNum, int time,string &input)
{
this_thread::sleep_for(chrono::milliseconds(time)); //Sleep thread
cout << "Producer Thread - " << thrNum << " starts sleeping for " << time << "milliseconds" << endl;
//sleepThr(thrNum, time);
mtx_blockMyQue.lock(); //Thread locked
if (myQue.isEmpty()==false)
{
cout << "Producer Thread - " << thrNum << " is now enqueuing '" << input << "'" << endl;
//Value to be dequeued and then to be enqueued
//Dequeueing the value
mainQue.enqueue(input); //Enqueueing the value
}
mtx_blockMyQue.unlock(); //Thread unlocked
//mtx_blockPrint.lock(); //Thread locked
this_thread::sleep_for(chrono::milliseconds(time)); //Sleep thread
cout << "Producer Thread - " << thrNum << " starts sleeping for " << time << "milliseconds" << endl;
//mtx_blockPrint.unlock(); //Thread unlocked
}
//What consumer threads do
void consumer(Queue &mainQue, int thrNum , int time , string &input, fstream &reader)
{
//this_thread::sleep_for(chrono::milliseconds(time)); //Sleep thread
//cout << "Consumer Thread - " << thrNum << " starts sleeping for " << time << "milliseconds" << endl;
mtx_blockPrint.lock(); //Thread locked
this_thread::sleep_for(chrono::milliseconds(time)); //Sleep thread
cout << "Consumer Thread - " << thrNum << " starts sleeping for " << time << "milliseconds" << endl;
mtx_blockPrint.unlock(); //Thread unlocked
mtx_blockMainQue.lock();
cout << "Consumer Thread - " << thrNum << " is now handling '" << input << "'" <<endl;
string line;
reader.open(input);
if (!reader.is_open())
{
cout << "Consumer Thread - " << thrNum << " cannot process '" << input << "', there is no such file!" << endl;
}
else
{
getline(reader, line, '.'); //Read file ignoring '.'
char mostChr = mostFrequent(line); //The most frequent char
char e = 'e';
int intChr = mostChr; //Decimal of the most frequent char
int intE = e; //Decimal of the char 'e'
int shiftNum = intChr - intE; //Shift number
decipher(line, shiftNum); //Decrypting the message
string outputFile = input + "_decrypted.txt";
ofstream output(outputFile); //Opening a new output file for decrypted message
output << line; //Putting the decrypted message into the file
output.close(); //Closing the output file
cout << "Consumer Thread - " << thrNum << " is done handling " << input << " with a shift of " << shiftNum << " and written the result to '" << outputFile << "'" << endl;
}
reader.close();
mtx_blockMainQue.unlock();
}
int main() {
fstream reader; //Reader
string inputFileName; //File name
int time1[2], time2[3];
cout << "Enter a file name: ";
cin >> inputFileName;
myQue.enqueue(inputFileName); //Storing the file name in my structure
//Do this task until the dash(-) character entered
while(inputFileName != "-")
{
cout << "Enter a file name: ";
cin >> inputFileName;
myQue.enqueue(inputFileName);
}
thread prodThr[2]; //Constructing Producer Threads
thread consThr[3]; //Constructing Consumer Threads
/*
for (int i = 0; i < 1; i++) {
time1[i] = Ran.RandInt(1000, 4000);
prodThr[i] = thread(&sleepThr, i + 1, time1[i]);
}
for (int i = 0; i < 2; i++)
{
time2[i] = Ran.RandInt(2500, 3500);
consThr[i] = thread(&sleepThr, i + 1, time2[i]);
}
*/
while (myQue.isEmpty() == false)
{
for (int i = 0; i<2; i++) {
time1[i] = Ran.RandInt(1000, 4000);
myQue.dequeue(inputFileName);
prodThr[i] = thread(&producer, myQue, mainQue, i + 1, time1[i], inputFileName);
}
for (int i = 0; i<3; i++) {
time2[i] = Ran.RandInt(2500, 3500);
if (mainQue.isEmpty() == false)
{
mainQue.dequeue(inputFileName);
consThr[i] = thread(&consumer, mainQue, i + 1, time2[i], inputFileName, reader);
}
}
//Joining Producer Threads
for (int i = 0; i < 2; i++) {
prodThr[i].join();
}
//Joining Consumer Threads
for (int i = 0; i<3; i++) {
consThr[i].join();
}
}
return 0;
}
Queue.cpp
#include <iostream>
#include "Queue.h"
using namespace std;
//************************************************
// Constructor. Generates an empty queue *
//************************************************
Queue::Queue()
{
front = nullptr;
rear = nullptr;
}
//********************************************
// Function enqueue inserts the value in num *
// at the rear of the queue. *
//********************************************
void Queue::enqueue(string val)
{
if (isEmpty()) //if the queue is empty
{ //make it the first element
front = new QueueNode(val);
rear = front;
}
else //if the queue is not empty
{ //add it after rear
rear->next = new QueueNode(val);
rear = rear->next;
}
}
//**********************************************
// Function dequeue removes the value at the *
// front of the queue, and copies it into num. *
//**********************************************
void Queue::dequeue(string &val)
{
QueueNode *temp;
if (isEmpty())
{
exit(1);
}
else //if the queue is not empty
{ //return front's value, advance front and delete old front
val = front->value;
temp = front;
front = front->next;
delete temp;
}
}
//*********************************************
// Function isEmpty returns true if the queue *
// is empty, and false otherwise. *
//*********************************************
bool Queue::isEmpty() const
{
if (front == nullptr)
return true;
else
return false;
}
//********************************************
// Function clear dequeues all the elements *
// in the queue. *
//********************************************
void Queue::clear()
{
string val; // Dummy variable for dequeue
while(!isEmpty())
dequeue(val); //delete all elements
}
Queue.h
#ifndef DYNINTQUEUE_H
#define DYNINTQUEUE_H
#include <string>
using namespace std;
struct QueueNode
{
string value;
QueueNode *next;
QueueNode(string val, QueueNode *ptr = nullptr)
{
value = val;
next = ptr;
}
};
class Queue
{
private:
// These track the front and rear of the queue.
QueueNode *front;
QueueNode *rear;
public:
// Constructor.
Queue();
// Member functions.
void enqueue(string);
void dequeue(string &);
bool isEmpty() const;
void clear();
};
#endif
randgen.cpp
#include <time.h> // for time()
#include <stdlib.h> // for rand/srand
#include "randgen.h"
#include <cmath>
#include <iostream>
using namespace std;
int RandGen::ourInitialized = 0;
void RandGen::SetSeed(int seed)
// postcondition: system srand() used to initialize seed
// once per program (this is a static function)
{
if (0 == ourInitialized)
{ ourInitialized = 1; // only call srand once
srand(seed); // randomize
}
}
RandGen::RandGen()
// postcondition: system srand() used to initialize seed
// once per program
{
if (0 == ourInitialized)
{ ourInitialized = 1; // only call srand once
time_t now;
time (&now); // localtime bir zamandan itibaren geçen saniye formatında
// now değişkenine kaydedilir.
srand(int((sin(double(now))*1000000)));//Gökhan
// seed'imiz her saniye bir artmasın diye
// daha random artsın diye sinusunu alıyorum
// srand(unsigned(time(0))); // randomize
}
}
int RandGen::RandInt(int max)
// precondition: max > 0
// postcondition: returns int in [0..max)
{
return int(RandReal() * max);
}
int RandGen::RandInt(int low, int max)
// precondition: low <= max
// postcondition: returns int in [low..max]
{
return low + RandInt(max-low+1);
}
double RandGen::RandReal()
// postcondition: returns double in [0..1)
{
return rand() / (double(RAND_MAX) + 1);
}
double RandGen::RandReal(double low, double high)
{
double width = fabs(high-low);
double thelow = low < high ? low : high;
return RandReal()*width + thelow;
}
randgen.h
#ifndef _RANDGEN_H
#define _RANDGEN_H
#include <limits.h> // for INT_MAX
// designed for implementation-independent randomization
// if all system-dependent calls included in this class, then
// other classes can make use of this class in independent manner
// all random numbers are uniformly distributed in given range
//
// RandGen() --- constructor sets seed of random # generator
// once per program, not per class/object
//
// RandInt(int max)
// RandInt(int low,int max) - return random integer in range [0..max)
// when one parameter used, [low..max] when
// two parameters used
//
// examples: rnd.RandInt(6) is random integer [0..5] or [0..6)
// rnd.RandInt(3,10) is random integer [3..10]
// rnd.RandInt() is random integer [0..INT_MAX)
//
// RandReal() -- returns random double in range [0..1)
// RandReal(double low, double max) -- random double in range [low..max)
class RandGen
{
public:
RandGen(); // set seed for all instances
int RandInt(int max = INT_MAX); // returns int in [0..max)
int RandInt(int low, int max); // returns int in [low..max]
double RandReal(); // returns double in [0..1)
double RandReal(double low, double max); // range [low..max]
static void SetSeed(int seed); // static (per class) seed set
private:
static int ourInitialized; // for 'per-class' initialization
};
#endif
I have checked everything but I cannot understand why the compiler gives me this error. I am using Microsoft Visual Studio 2015.
Upvotes: 0
Views: 1337
Reputation: 20936
Read about thread
constructor (here) and reference_wrapper
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).
Signature of your function is
void producer(Queue &myQue, Queue &mainQue , int thrNum, int time,string &input)
so you have to change the call of thread constructor to
prodThr[i] = thread(&producer, std::ref(myQue), std::ref(mainQue),
i + 1, time1[i], std::ref(inputFileName));
do the same for consumer
function.
Upvotes: 2