Having problems with executing jobs using fork. The code is supposed to create one job and execute one job and repeat this multiple times. We are only supposed to use usleep in the jobgeneration() function.

We are having trouble sleeping and executing ctrl-c in the execute job function.

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <iterator>
#include <vector>
#include <map>
#include <signal.h>
#include <unistd.h>

using namespace std;

void jobScheduler();
void setJobQueues();
void jobGenerator(int maximumQueueSize);
int createRandomJob();
int createRandomQuatnumInteger();
int selectJob();
void executeJob(int jobnumber);
string convertInt(int number);

int main() {
	int pid; 
	int MAX_JOB_QUEUE_SIZE = 10;
	srand(time(0));
	// DONT UNCOMMENT SETJOBQUEUES!
	//setJobQueues(); //Set up the priority job queues with chosen file and data structure
	////////////////////////////////
	
	//jobGenerator(10);
	//selectJob();
	//jobScheduler();
	
	if(pid = fork() != 0){ //Parent, jobGenerator process
		cout<<":pid from if "<<pid<<endl;
		jobGenerator(MAX_JOB_QUEUE_SIZE); //generate random jobs and put them into priority queues. The priority queues must be protected in a critical region.
		//exit(0);
	}
	else{ //Child, job scheduler process
		cout<<":pid from else"<<pid<<endl;
		jobScheduler(); //schedule and execute the jobs
		exit(0);
	}
	
	//jobScheduler();
	return 1;
}

void setJobQueues(){
	ofstream file("queues.txt");
	file<<endl<<endl<<endl;
	file.close();
}

void jobGenerator(int maximumQueueSize){
	int number = 0;
	for(int i = 0; i<10; i++)
	{
		number = createRandomJob();
		string numberString = convertInt(number);
		cout<<"the number generated is "<<number<<endl;
		//cout<<"numberString="<<numberString<<endl;
		ifstream input;
		input.open("queues.txt", ifstream::in);
		
		string lineTask = "";
		string lineServer = "";
		string linePowerUser = "";
		string lineUser = "";
		
		int lineNumber = 0;
		getline(input, lineTask);
		getline(input, lineServer);
		getline(input, linePowerUser);
		getline(input, lineUser);
			
		/*cout<<"before\n";
		cout<<"line 1"<<lineTask<<endl;
		cout<<"line 2"<<lineServer<<endl;
		cout<<"line 3"<<linePowerUser<<endl;
		cout<<"line 4"<<lineUser<<endl;*/
		
		if(lineTask.length() == (maximumQueueSize*2)){
			//cout<<"line is equal to max\n";
		}
		else if(lineTask.length() < (maximumQueueSize*2)){
			if(number>=1 && number <=10){ //add to task queue
					//cout<<"enter1\n";
					lineTask.append(numberString+"|");
			}
		}
		
		if(lineServer.length() == (maximumQueueSize*2)){
			//cout<<"line is equal to max\n";
		}
		else if(lineServer.length() < (maximumQueueSize*2)){
			if(number>=11 && number <=30){ //add to server queue
					//cout<<"enter2\n";
					int quant = createRandomQuatnumInteger();
					string quantum = convertInt(quant);
					lineServer.append(numberString+":"+quantum+"|");
			}
		}
		
		if(linePowerUser.length() == (maximumQueueSize*2)){
			//cout<<"line is equal to max\n";
		}
		else if(linePowerUser.length() < (maximumQueueSize*2)){
			if(number>=31 && number <=50){ //add to power user queue
					//cout<<"enter3\n";
					linePowerUser.append(numberString+"|");
			}
		}
		
		if(lineUser.length() == (maximumQueueSize*2)){
			//cout<<"line is equal to max\n";
		}
		else if(lineUser.length() < (maximumQueueSize*2)){
			if(number>=51 && number <=100){ //add to user queue
					//cout<<"enter4\n";
					lineUser.append(numberString+"|");
			}
		}
		input.close();
		ofstream output;
		output.open("queues.txt", ofstream::out);
		
		/*cout<<"after\n";
		cout<<"line 1"<<lineTask<<endl;
		cout<<"line 2"<<lineServer<<endl;
		cout<<"line 3"<<linePowerUser<<endl;
		cout<<"line 4"<<lineUser<<endl;*/
		output<<lineTask<<endl;
		output<<lineServer<<endl;
		output<<linePowerUser<<endl;
		output<<lineUser;
		output.close();
		usleep(50);
	}
}

void jobScheduler(){
	int i = 0;
	int n = 0; 
	int pid;
	while(i<10){ //schedule and run maximum N jobs
		n = selectJob(); //pick a job from the priority queues
		cout<<"job is"<<n<<endl;
		if(n > 0){ //valid job id
			if(pid = fork() == 0){ //child worker process
				executeJob(n); //execute job
				exit(0);
			}
			else
			{
				cout<<"enter else\n";
			}
		}
		i++;
	}
	
}

int createRandomJob(){
	int randomNumber = 0;
	randomNumber = rand() % 100 + 1; //return number between range 1 to 100
	return randomNumber;
}

int createRandomQuatnumInteger(){
	int randomNumber;
	//srand(time(NULL)); //initialize random seed
	randomNumber = rand() % 3; //return number between range 1 to 100
	return randomNumber;
}

string convertInt(int number){
   stringstream ss;	//create a stringstream
   ss << number;	//add number to the stream
   return ss.str();	//return a string with the contents of the stream
}

void signalCall(int param)  {
     cout << endl << "Resuming Execution..." << endl;
     sleep(1);
     signal(SIGINT, SIG_DFL);
}

void executeJob(int jobNumber){

	// If job ID is in task_queue just print the job id
    if(jobNumber >=1 && jobNumber <=10){
         cout << endl << "TASK_QUEUE - JOB ID: " << jobNumber << endl;         
    }

	// If job ID is in server_queue have it run and print its number also say its round robin
    if(jobNumber >=11 && jobNumber <=30){
         cout << endl << "SERVER_QUEUE - JOB ID: " << jobNumber << endl;         
    }
    
	// if job ID is in power_user queue block here for the CNTRL C user input
    if(jobNumber >=31 && jobNumber <=50){
        cout << endl << "POWER_USER_QUEUE - JOB ID: " << jobNumber << endl;  
        cout << "Hit CNTL C to continue" << endl;
        
        signal(SIGINT,signalCall);
    }

	// if job ID is in user_queue run then sleep for 5 seconds 
    if(jobNumber>=51 && jobNumber <=100){
         cout << endl << "USER_QUEUE - JOB ID: " << jobNumber << endl;         
         sleep(5);
    }
}

// Splits the line in the file up so we can get at each job
// This is reused from the first project
inline vector<string> split(const string& s, const string& f) {
	vector<string> temp;
	if (f.empty()) {
		temp.push_back(s);
		return temp;
	}
	// Iterator to go throught the string
	typedef string::const_iterator iter;
	const iter::difference_type f_size(distance(f.begin(), f.end()));
	iter i(s.begin());
	for (iter pos; (pos = search(i, s.end(), f.begin(), f.end())) != s.end();) {
		temp.push_back(string(i, pos));
		advance(pos, f_size);
		i = pos;
	}
	temp.push_back(string(i, s.end()));
	return temp;
}

// This one checks that file for jobs.  It should first look at the top line since that is highest priority.  THen it will move on down.  
// I know I made all my functions void, but you'll have to change return types to match things.   
// Select job should return the job ID 
int selectJob() {
	int lineNumber = 0;
	string line = "";
	int jobID;
	string IDs[4];

    // Open the file so we can read from it
	ifstream input ("queues.txt");

    // Get 4 lines from the file and store each as an entry in the IDs array
	for (int i = 0; i < 4; i++) {
		getline(input, line);
		IDs[lineNumber] = line;
		lineNumber++;
	}
	
	input.close();
	
	// Just for testing
	/*cout << endl;
	for (int i = 0; i < 4; i++) {
		cout << "Line" << i+1 << ": "<< IDs[i] << endl;
	}
	cout << endl;*/
	
	/////////////////////
	// Line 1 TASK_QUEUE/
	/////////////////////
	if (IDs[0].length() > 1) {
		//cout<<"TASK QUEUE\n";
		// call the split function to make a vector of each process ID
		const vector<string> jobs(split(IDs[0], "|"));
		//cout<<"numbernumbernumber"<<jobs[0].c_str()<<endl;
		jobID = atoi(jobs[0].c_str()); // Converts the string to an int

        // Cut the job out of the file and assign the new job list in its place
		string newString = IDs[0].substr(jobs[0].length() + 1, IDs[0].length());
		//cout<<"the new string from 1 is"<<newString<<endl;
		IDs[0] = newString;

        // Open the file and clear it
        // Then rewrite the updated information to it
		ofstream output;
		output.open("queues.txt", ofstream::out | ios::trunc);
		for (int i = 0; i < 4; i++) {
			output << IDs[i] << endl;
			//cout<<"the data being written to the file from 1 is"<<IDs[i]<<endl;
		}

		output.close();
		
		return jobID;
		//exit(0);
	}

// REMOVE JOB WHEN QUANT IS ZERO

	///////////////////////
	// Line 2 SERVER_QUEUE/
	///////////////////////
	if (IDs[1].length() > 1) {
		// call the split function to make a vector of each process ID
		const vector<string> jobs(split(IDs[1], "|"));

		// Split it again but with the : for the quantum time
		const vector<string> quantum(split(jobs[0], ":"));
		//cout<<"numbernumbernumber"<<jobs[1].c_str()<<endl;
		int quant = atoi(quantum[1].c_str());  // Converts the string to an int
		quant--; // Decrease the quantum time by 1

		jobID = atoi(jobs[0].c_str());  // Converts the string to an int

		//cout << "JOBID: " << jobID << endl;
		//cout << "quant: " << quant << endl;

        // Cut the job out of the file and assign the new job list in its place
		string newString = IDs[1].substr(jobs[0].length() + 1, IDs[1].length());
		//cout<<"the new string is"<<newString<<endl;

        // These two calls to stringstream as used to convert the integer 
        // values into strings that we can concatenate to put back into the file
		string jobIDString;
		stringstream out;
		out << jobID;
		jobIDString = out.str();

		string quantString;
		stringstream out2;
		out2 << quant;
		quantString = out2.str();

        // Append the job and the decremented quantum time to the end
        // of the queue
		if(quant > 0) {
			newString = newString + jobIDString + ":" + quantString + "|";
		}

		//cout << endl << endl << newString << endl;

		IDs[1] = newString;

        // Open the file and clear it
        // Then rewrite the updated information to it
		ofstream output;
		output.open("queues.txt", ofstream::out | ios::trunc);
		for (int i = 0; i < 4; i++) {
			output << IDs[i] << endl;
			//cout<<"the data being written to the file from 2 is"<<IDs[i]<<endl;
		}
		
		output.close();

		return jobID;
		//exit(0);
	}

	///////////////////////////
	// Line 3 POWER_USER_QUEUE/
	///////////////////////////
	if (IDs[2].length() > 1) {
		// call the split function to make a vector of each process ID
		const vector<string> jobs(split(IDs[2], "|"));
		//cout<<"numbernumbernumber"<<jobs[2].c_str()<<endl;

		jobID = atoi(jobs[0].c_str());  // Converts the string to an int

        // Cut the job out of the file and assign the new job list in its place
		string newString = IDs[2].substr(jobs[0].length() + 1, IDs[2].length());
		//cout<<"the new string from 3 is"<<newString<<endl;
		IDs[2] = newString;

        // Open the file and clear it
        // Then rewrite the updated information to it
		ofstream output;
		output.open("queues.txt", ofstream::out | ios::trunc);
		for (int i = 0; i < 4; i++) {
			output << IDs[i] << endl;
			//cout<<"the data being written to the file from 3 is"<<IDs[i]<<endl;
		}

		output.close();
		
		return jobID;
		//exit(0);
	}

	/////////////////////
	// Line 4 USER_QUEUE/
	/////////////////////
	if (IDs[3].length() > 1) {
		// call the split function to make a vector of each process ID
		const vector<string> jobs(split(IDs[3], "|"));

		jobID = atoi(jobs[0].c_str());  // Converts the string to an int
		//cout<<"numbernumbernumber"<<jobs[3].c_str()<<endl;
        // Cut the job out of the file and assign the new job list in its place
		string newString = IDs[3].substr(jobs[0].length() + 1, IDs[3].length());
		//cout<<"the new string from 4 is"<<newString<<endl;
		IDs[3] = newString;

        // Open the file and clear it
        // Then rewrite the updated information to it
		ofstream output;
		output.open("queues.txt", ofstream::out | ios::trunc);
		for (int i = 0; i < 4; i++) {
			output << IDs[i] << endl;
			//cout<<"the data being written to the file from 4 is"<<IDs[i]<<endl;
		}

		output.close();
		
		return jobID;
		//exit(0);
	}

	else {
		return -1;
	}
}

Any suggestions?

Here is the assignment:

Process Scheduling Project on

Write a C/C++ Process Scheduler program on UNIX to simulate the round robin priority scheduler with four queues: TASK_QUEUE, SERVER_QUEUE, POWER_USER_QUEUE, and USER_QUEUE.
The program should create the following processes (or threads) for the scheduler simulation:

1. The job-generation process (or thread) will randomly generate new jobs and put them into the job queues. The new jobs can be simple print and sleep/usleep operations.
The job queues may be stored in an external file so that it can be accessed by other process if processes are used (or store in an array of list if threads are used).

2. The scheduler process (or thread) will select a job from the job queues and create a new work process (or thread) to run the job. The scheduler will use the following scheduling algorithm:

a. Jobs in the TASK_QUEUE have the highest priority. These jobs will be run until finished.

b. Jobs in the SERVER_QUEUE have the second priority. These jobs will be run using the round robin algorithm.
(You should attach a random number from 1 to 3 with the job to indicate the number of quantum times that the job needed to be run to finish.)

c. Jobs in the POWER_USER_QUEUE have the third priority. These jobs will be run and then blocked for the input. It will become ready to run again when user types the interrupt key ^C, then it will be run to the finish.
(See the signal demo on the third semaphore method on semaphore demo page for interrupt key implementation.)

d. Jobs in the USER_QUEUE have the lowest priority. These jobs will be run once and then sleep for 5 seconds and then run to finish.

Before scheduling the next job, the scheduler will check whether a new higher priority job is available. It always schedules the next job with the highest priority.

Please don't use infinite loop to generate the processes/threads. You should control the number of processes/threads generated by a counter.

3. Both the job-generation and scheduler processes (or threads) will access the job queues. You must avoid the race condition by put the job queues into a critical region. (You may use semaphores or monitors to protect the critical region.)

Testing Requirements:

1. Randomly create jobs for the TASK_QUEUE, SERVER_QUEUE, and USER_QUEUE to test your scheduler. For example, you may generate random job numbers between 1 to 100 and assign the job with random numbers between 1 to 10 to the task queue, 11 to 30 to the server queue, 31 to 50 to the power user queue, and 51 to 100 to the user queue.
Each queue should have a MAX_JOB_QUEUE size to limit the number of jobs.
You should use the sleep() function to control the speed of the simulation.

2. Print out each step of the job execution.

a. A Priority Scheduler using multiple processes

int main() {
…
setJobQueues();           /* Set up the priority job queues with chosen file and data structure */
if (pid=fork() != 0) {/* Parent, jobGenerator process */
    jobGenerator(…); /* generate random jobs and put them into the priority queues
                                         The priority queues must be protected in a critical region */
} else {/* Child, job scheduler process */
    jobScheduler(…); /* schedule and execute the jobs. */
    exit(0);
}
return (1);
}
void jobScheduler(…) {
…
while (i < N) { /* schedule and run maximum N jobs */
    n=selectJob(…)       /* pick a job from the job priority queues */
    if (n>0) { /* valid job id */
                        if (pid = fork() == 0) { /* child worker process */
                            executeJob (…);      /* execute the job */
                            exit(0);
                        }
   }
}

Hi,

This is little bit big project. You have to give effort, and i can only give guidelines.

First of all, I would suggest to use the thread to do this project, not the process.

you need to learn following things:

1) C++ basics, (inheritance)
2) threads (start, stop and locking), pthread can be a good start.
3) Fileinput, output . as you have to read jobs from a file

Now,

Start designing your class diagrams for this project. We can use template or inheritance to do this things.

I would suggest go for inheritance first, then when you will understand the architecture then try to implement a template.
here is a guideline (inheritence based )which you might want to follow:

1) A job class, if there are several kind of job class, then first right a Job Abstract class and inherits your different type of child job class from the abstract job class.

class Job{
     virtual execute() = 0;
}

class printjob: public Job{
     virtual execute(){
       //printf
     }
}


class sleepJob: public Job{
     virtual execute(){
       //sleep
     }
}

So now you have the job classes.

Now for your process management, right a abstract thread class:

class Thread{
          virtual Run()=0
}

Your every process type class will inherit this class with their own run() method for their specific responsibility.

YOU ARE STILL WITH ME? :)

So once you are done with these TWO class hierarchy then everything else is simple.

I would suggest to start writing with a simple c++ thread class, and see how it works.

So our ultimate goal is,

We will use C++ container Queue to store different priority jobs.
Our Thread classes to do their work.
Our job classes to perform their job.

Just not to scare you, here is an example of the pthread class, you have to extend it for your purpose:

#ifndef THREAD_H_
#define THREAD_H_

#include <pthread.h>

class PThread{
	pthread_t thread_id;

public:

	void Start(){
		pthread_create( &thread_id, NULL, EntryPoint, (void *)this);
	}
	static void *EntryPoint(void *thread){
		PThread *self = static_cast<PThread *>(thread);

		self->Run();
	}
	virtual void Run() = 0;
};


class JobSchedular: public PThread{
	virtual void Run(){
		for(int i = 1; i <= 10; i++){
			cout << "scheduling job" << endl;
			sleep(1);
		}
	}
};

call it from main like this:

JobSchedular  schedular;

schedular.start();

Think about it and let me know if you have any question.

This is due by tonight.... So, don't have enough time to start with threading. We seem to have the sleep on the third job queue working. The only problem is the ctrl-c. Ctrl-c is also the terminator for a process in UNIX. I think that may be the problem.

This article has been dead for over six months. Start a new discussion instead.