I have the following code that initializes a shared memory containing 1 mutex and 1 condition variable then forks a process where the parent passes to the child some characters through a pipe and signals the child to go an read it.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <pthread.h>
#ifndef _POSIX_THREAD_PROCESS_SHARED
#error This system does not support process shared mutex
#endif
pthread_cond_t *cvptr; //Condition Variable Pointer
pthread_condattr_t cattr; //Condition Variable Attribute
pthread_mutex_t *mptr; //Mutex Pointer
pthread_mutexattr_t matr; //Mutex Attribute
int shared_mem_id; //shared memory Id
int *mp_shared_mem_ptr; //shared memory ptr -- pointing to mutex
int *cv_shared_mem_ptr; //shared memory ptr -- pointing to condition variable
/* Read characters from the pipe and echo them to stdout. */
void read_from_pipe (int file)
{
printf("read_from_pipe()\n");
FILE *stream;
int c;
stream = fdopen (file, "r");
// Lock mutex and then wait for signal to relase mutex
printf("child mutex lock \n");
pthread_mutex_lock( mptr );
printf("child mutex locked\n");
printf("child wait\n");
pthread_cond_wait( cvptr, mptr );
printf("child condition woke up\n");
while ((c = fgetc (stream)) != EOF)
putchar (c);
fclose (stream);
printf("child mutex unlock\n");
pthread_mutex_unlock( mptr );
}
/* Write some random text to the pipe. */
void write_to_pipe (int file)
{
printf("write_to_pipe()\n");
FILE *stream;
stream = fdopen (file, "w");
fprintf (stream, "hello, world!\n");
fprintf (stream, "goodbye, world!\n");
fclose (stream);
pthread_cond_signal( cvptr );
}
int main (void)
{
int rtn;
size_t shm_size;
/* initialize shared memory segment */
shm_size = 1*sizeof(pthread_mutex_t) + 1*sizeof(pthread_cond_t);
if ((shared_mem_id = shmget(IPC_PRIVATE, shm_size, 0660)) < 0)
{
perror("shmget"), exit(1) ;
}
if ((mp_shared_mem_ptr = (int *)shmat(shared_mem_id, (void *)0, 0)) == NULL)
{
perror("shmat"), exit(1);
}
//Offset to find the location of the condition variable in the shared memory
unsigned char* byte_ptr = reinterpret_cast<unsigned char*>(mp_shared_mem_ptr);
byte_ptr += 1*sizeof(pthread_mutex_t);
mptr = (pthread_mutex_t *)mp_shared_mem_ptr;
cvptr = (pthread_cond_t *)byte_ptr;
// Setup Mutex
if (rtn = pthread_mutexattr_init(&matr))
{
fprintf(stderr,"pthreas_mutexattr_init: %s",strerror(rtn)),exit(1);
}
if (rtn = pthread_mutexattr_setpshared(&matr,PTHREAD_PROCESS_SHARED))
{
fprintf(stderr,"pthread_mutexattr_setpshared %s",strerror(rtn)),exit(1);
}
if (rtn = pthread_mutex_init(mptr, &matr))
{
fprintf(stderr,"pthread_mutex_init %s",strerror(rtn)), exit(1);
}
//Setup Condition Variable
if(rtn = pthread_condattr_init(&cattr))
{
fprintf(stderr,"pthread_condattr_init: %s",strerror(rtn)),exit(1);
}
if(pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))
{
fprintf(stderr,"pthread_condattr_setpshared %s",strerror(rtn)),exit(1);
}
if(pthread_cond_init(cvptr, &cattr))
{
fprintf(stderr,"pthread_cond_init %s",strerror(rtn)),exit(1);
}
pid_t pid;
int mypipe[2];
/* Create the pipe. */
if (pipe (mypipe))
{
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
/* Create the child process. */
pid = fork ();
if (pid == (pid_t) 0)
{
printf ("Child Forked!.\n");
/* This is the child process.
Close other end first. */
close (mypipe[1]);
read_from_pipe (mypipe[0]);
return EXIT_SUCCESS;
}
else if (pid < (pid_t) 0)
{
/* The fork failed. */
fprintf (stderr, "Fork failed.\n");
return EXIT_FAILURE;
}
else
{
printf ("Parent Forked!.\n");
/* This is the parent process.
Close other end first. */
close (mypipe[0]);
write_to_pipe (mypipe[1]);
return EXIT_SUCCESS;
}
}
I think I did something wrong with the initialization of the variables, the code does not core dump but somehow only prints:
Parent Forked!.
write_to_pipe()
Any ideas?
It's possible that write_to_pipe is signalling the condition variable before read_from_pipe reaches the pthread_cond_wait. Condition variables don't do any kind of buffering or counting of signals, so it will simply be lost.
Related
I'm writing a program where there are two threads, the first thread scans an input file(one int per line) and assigns the number to a global variable. The second thread then reads the global variable and if it's even prints it twice to a file and if odd prints it only once.
For example if the input file is:
1
2
3
then the output file should be:
1
2
2
3
Unfortunately what happens is that the output file comes out as:
3
Where can I position my mutex locks and unlocks in order to get the correct result?
Here is my code:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <cstdlib>
using namespace std;
FILE* ifile;
int variable = 0;
pthread_mutex_t thing;
struct arguments {
FILE* file;
};
void* meth1(void* param) {
ifile = fopen("intput.txt", "r");
if (ifile == NULL) {
printf("couldn't open the file");
return 0;
}
pthread_mutex_lock(&thing);
while (!feof(ifile)) {
fscanf(ifile, "%d\n", &variable);
}
pthread_mutex_unlock(&thing);
return NULL;
}
void* meth2(void* param) {
if (variable % 2 == 0) {
pthread_mutex_lock(&thing);
fprintf((FILE*)param, "%d\n", variable);
fprintf((FILE*)param, "%d\n", variable);
pthread_mutex_unlock(&thing);
}
if (variable % 2 != 0) {
pthread_mutex_lock(&thing);
fprintf((FILE*)param, "%d\n", variable);
pthread_mutex_unlock(&thing);
}
return NULL;
}
int main() {
FILE* ofile;
ofile = fopen("output.txt", "w");
if (ofile == NULL) {
printf("couldn't open the file");
return 0;
}
arguments args;
args.file = ofile;
pthread_t thread1;
pthread_create(&thread1, NULL, meth1, NULL);
pthread_join(thread1, NULL);
pthread_t thread2;
pthread_create(&thread2, NULL, meth2, args.file);
pthread_join(thread2, NULL);
fclose(ofile);
pthread_mutex_destroy(&thing);
return 0;
}
In your for loop you do this:
pthread_mutex_lock(&thing);
while (!feof(ifile)) {
fscanf(ifile, "%d\n", &variable);
}
pthread_mutex_unlock(&thing);
So, you're consuming the whole file and assigning to the variable on each loop.
There is no opportunity for writing anything other than 3.
EDIT:
The following code doesn't directly answer the question but it is a solution to your problem.
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
int main()
{
fstream f_input;
fstream f_output;
/* Open input file */
f_input.open("input.txt",ios::in);
if (!f_input.is_open())
{
cout << "Unable to open input file" << endl;
return 0;
}
/* Open out file */
f_output.open("output.txt",ios::out);
if (!f_output.is_open())
{
cout << "Unable to open output file" << endl;
return 0;
}
/* Iterate thru the file per line*/
string last_line;
char *p_last_line;
int i_last_line_integer;
unsigned int ui_last_line_len;
do
{
getline(f_input, last_line);
p_last_line = (char *)last_line.data();
sscanf(p_last_line,"%d", &i_last_line_integer);
ui_last_line_len = last_line.length();
if (i_last_line_integer %2 == 0) /* it's even, write twice */
{
f_output.write(p_last_line,ui_last_line_len);
f_output.write("\n", ui_last_line_len);
f_output.write(p_last_line,ui_last_line_len);
f_output.write("\n", ui_last_line_len);
}
else /* it's odd, write once */
{
f_output.write(p_last_line,ui_last_line_len);
f_output.write("\n", ui_last_line_len);
}
}while(!f_input.eof());
f_input.close();
f_output.close();
return 0;
}
OLD:
I see you call the join function immediately after creating the first thread. The join function waits to the thread to end, so if you want both threads to run at once you should use rewrite that section of code to this:
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, meth1, NULL);
pthread_create(&thread2, NULL, meth2, args.file);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
However I don't think that is what you really want to accomplish, do you want the code to first read the first file and output the numbers into the second file? If so, you could just open both files at once and print into the second file each loop after you read the variable, because your second thread at the moment really only executes once.
Now the next code is how you should use the mutexes to prevent variable to be accessed from both threads at once but doesn't fix the algorithm if it's job is to read and copy to another file in case the left over from division is 0:
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <cstdlib>
using namespace std;
FILE *ifile;
int variable = 0;
pthread_mutex_t thing;
struct arguments
{
FILE *file;
};
void *meth1(void *param)
{
ifile = fopen("intput.txt", "r");
if (ifile == NULL)
{
printf("couldn't open the file");
return 0;
}
while (!feof(ifile))
{
pthread_mutex_lock(&thing);
fscanf(ifile, "%d\n", &variable);
pthread_mutex_unlock(&thing);
}
return NULL;
}
void *meth2(void *param)
{
pthread_mutex_lock(&thing);
if (variable % 2 == 0)
{
fprintf((FILE *)param, "%d\n", variable);
fprintf((FILE *)param, "%d\n", variable);
}
else
{
fprintf((FILE *)param, "%d\n", variable);
}
pthread_mutex_unlock(&thing);
return NULL;
}
int main()
{
FILE *ofile;
ofile = fopen("output.txt", "w");
if (ofile == NULL)
{
printf("couldn't open the file");
return 0;
}
arguments args;
args.file = ofile;
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, meth1, NULL);
pthread_create(&thread2, NULL, meth2, args.file);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
fclose(ofile);
pthread_mutex_destroy(&thing);
return 0;
}
How to use the function of "CreatePipe" and "CreateProcessW" in Linux, when I compile the C++ code in Linux, there have some errors as follow: 'CreatePipe' was not declared in this scope. 'CreateProcessW' was not declared in this scope.
Posix/Linux:
int pipe(int pipefd[2]);
pipefd[0] refers to the read end of the pipe.
pipefd[1] refers to the write end of the pipe.
Linux specific:
int pipe2(int pipefd[2], int flags);
When it comes to CreateProcess, the Posix/Linux version is done in a few steps.
Call fork() to create a new process - still running the same program - so two processes will now continue running the same program from the same point where fork() was called. Determining if it's the parent process or child process is done by checking the return value (the process id) from fork().
dup the file descriptors returned by pipe using int dup2(int oldfd, int newfd); to replace stdin and stdout for the new process.
Execute a program in the new process using one of the exec* functions.
// create pipes here
if(pid_t pid = fork(); pid == -1) {
// fork failed
} else if(pid == 0) { // child process goes here (with a new process id)
// dup2(...)
// exec*()
} else { // parent process goes here
// do parenting stuff
}
Example:
#include <unistd.h>
#include <sys/types.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
struct Pipe {
Pipe() {
if(pipe(io)) throw std::runtime_error("pipe failure");
}
~Pipe() {
close_rd();
close_wr();
}
void close_rd() { closer(io[0]); }
void close_wr() { closer(io[1]); }
int rd() { return io[0]; }
int wr() { return io[1]; }
private:
void closer(int& fd) {
if(fd != -1) {
close(fd);
fd = -1;
}
}
int io[2];
};
int main() {
Pipe parent_write, parent_read;
if(pid_t pid = fork(); pid == -1) {
// fork failed
return 1;
} else if(pid == 0) { // child process goes here (with a new process id)
// close file descriptors we don't need:
parent_write.close_wr();
parent_read.close_rd();
// duplicate into the place where stdin/stdout was
dup2(parent_write.rd(), fileno(stdin));
dup2(parent_read.wr(), fileno(stdout));
// execute a program
execl("/bin/ls", "/bin/ls", nullptr);
// exec* functions never returns if successful, so if we get here, it failed:
std::exit(1);
} else { // parent process goes here
std::cout << "child process " << pid << " started\n";
}
// close file descriptors we don't need:
parent_write.close_rd();
parent_read.close_wr();
// read data from child process using the file descriptor in parent_read.rd()
char buf[1024];
ssize_t rv;
while((rv = read(parent_read.rd(), buf, 1024))) {
write(fileno(stdout), buf, static_cast<size_t>(rv));
}
// use write(parent_write.wr(), ...) to write to the child.
}
I'm investigating the use of PThread.
The main process opens the camera and gets a matrix. Then calls the thread that running job in robot and I want it to be parallel. Basically it works and runs. But still feel unprofessional- because of the bool.
In the code below, this is an example (with fprintf).
I'd love to know how I can fix it without harm parallelism.
In the next code I do not show the call to the robot or camera opening.
There is a feeling that a mutex is needed.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <opencv2/opencv.hpp>
#include <unistd.h> /// for sleep
bool inThread = false;
void *print_message_function( void *ptr );
int main()
{
char mkey = 0;
pthread_t thread1;
char *message1 = "Thread 1";
int iret1;
cv::Mat bgr_image = imread("image.bmp",cv::IMREAD_COLOR);
while(mkey!=27){
if(!inThread){
inThread = true;
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
}
printf("In Main");
imshow("mat", bgr_image);
mkey = cv:: waitKey(5);
}
return 0;
}
void *print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf("%s \n", message);
sleep(2);
inThread = false;
pthread_exit(NULL);
}
The code works great and does not fall, but it seems unprofessional. Is there a chance that when you update the flag, it will check what is in the flag and fall?
inThread is concurrently read/written so its access shall be protected.
Using a mutex this can for example be done like follows.
Define a global mutex and initialise it:
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
Include errno to be able to do convenient error checking/logging for the pthread_*() calls:
#include <errno.h>
Change this
if(!inThread){
inThread = true;
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
}
to become
errno = pthread_mutex_lock(&m);
if (errno) {
perror("pthread_mutex_lock() failed");
exit(EXIT_FAILURE);
}
if (!inThread) {
inThread = true;
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
...
}
else {
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
}
And change this
inThread = false;
to become
errno = pthread_mutex_lock(&m);
if (errno) {
perror("pthread_mutex_lock() failed");
exit(EXIT_FAILURE);
}
inThread = false;
errno = pthread_mutex_unlock(&m);
if (errno) {
perror("pthread_mutex_unlock() failed");
exit(EXIT_FAILURE);
}
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;
//first comannd to execute
void first(int pipeA[], char * command[]){
//redirect STDOUT to pipe[1] and close the pipe[0] we are not using
dup2(pipeA[1], 1);
close(pipeA[0]);
execvp(command[0], command);
printf(" first error ");
exit(127);
}
void second(int pipeA[], char * command2[]){
//redirect STDIN to pipe[0] and close the pipe[1] that we are not using
dup2(pipeA[0], 0);
close(pipeA[1]);
//This doesnt seem to be doing anything at times
execvp(command2[0], command2);
perror(" second error ");
exit(127);
}
int main(void)
{
char buf[1024];
char * command[1024];// this one is the first input usually 'cat file.txt'
//Use only one or the other, sort never works and 'grep U' works sometimes
char * command2[] = {(char *)"sort", (char *) NULL};// this is wants to sort the above 'command[1024]' and its use in the second function
//char * command2[] = {(char *)"grep",(char *)"U",(char *) NULL};// this is wants to grep the above 'command[1024]' and its use in the second function
//variables for forks and waits
pid_t pid;
pid_t pid2;
int status;
int status2;
//see if || exists not in use currently
bool pipeExists = false;
//create pipe
int pipeA[2];
pipe(pipeA);
//first line and ask for input,
cout<< "command: ";
while (fgets(buf,1024,stdin) != NULL)
{
buf[strlen(buf) -1] = 0;
//Save input into buf and tokenized? it
//NOT YET CATCHING ||, im only debugging and usually use use 'cat file.txt'
int number =0;
char * ptr;
ptr = strtok(buf, " ");
while(ptr != NULL){
command[number] = ptr;
ptr = strtok(NULL, " ");
number++;
}
//***************************************************************
//1. do the pipes go here or after the children?
//They seem to be working here but im not really sure where they should be
close(pipeA[0]);
close(pipeA[1]);
//create first child
if ((pid = fork()) <0)
printf("fork error");
else if (pid == 0)
{ /* child */
//create second child INSIDE ORIGINAL CHILD
//2. Is this correct? or is there not supposed to be grandchildren?
if ((pid2 = fork()) <0)
printf("fork 2 error");
else if (pid == 0)
{ /* child */
second(pipeA, command2);
printf("couldn't execute: %s");
exit(127);
}
//first command from buf
first(pipeA, command);
printf("couldn't execute: %s");
exit(127);
//3. Do I wait for this child aswell?
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
printf("waitpid error");
}
/* parent */
if ( (pid = waitpid(pid, &status, 0)) < 0)
printf("waitpid error");
printf("Command :");
//***************************************************************
//***************************************************************
//SECOND WAY OF DOING IT
// THIS WAY IT TRIGGERS WAITPID ERRORS.
/*
close(pipeA[0]);
close(pipeA[1]);
//create first child
if ((pid = fork()) <0)
printf("fork error");
else if (pid == 0)
{
first(pipeA, command);
printf("couldn't execute: %s");
exit(127);
}
//create second child INSIDE ORIGINAL CHILD
if ((pid2 = fork()) <0)
printf("fork 2 error");
else if (pid == 0)
{
second(pipeA, command2);
printf("couldn't execute: %s");
exit(127);
}
//3. Do I wait for this child aswell?
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
printf("waitpid error");
if ( (pid = waitpid(pid, &status, 0)) < 0)
printf("waitpid error");
printf("Command :");
*/
//***************************************************************
}
exit(0);
}
Pretty much what the code shows here with its questions.
I need to create a microshell that takes in a command ("cat file.txt") and execute it with execvp() and pipe it to another process and either "sort" or "grep U" or anyother.
It's just that my processes won't run correctly at time or wont display anything. I have closed pipes all over the place and nothing has happen.
Solution by OP.
This is the code that works for microshell.
I ended up with creating two processes in the original parents process.
Moving some variables inside the while loop and resetting them to work again. Also create the pipe everytime the code runs and close the pipes.
Created a waitpid() for both processes not just one.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
using namespace std;
//This function will execute the users first command.
//It takes in a pipe the command array and a boolean to check for piping
//If a pipe exists then the boolean is true and will dup() the STDOUT into the write part of the pipe
//We close unecessary parts of the pipe and execvp() the command in the command array
//there it some error checkink in case the command doesn't execute
void first_command(int pipeA[], char * command[], bool pipeExists){
if(pipeExists){
dup2(pipeA[1], 1);
close(pipeA[0]);
}
execvp(command[0], command);
printf("can not execute first command. \n");
exit(127);
}
//This function is only called in the main is a piping exists
//It takes in a pipe and a command array
//It dup() the STDIN from the read end of the pipe and closes the unsued end
//It will execute the command accorind to what was provided in the the pipe
void second_command(int pipeA[], char * command2[]){
dup2(pipeA[0], 0);
close(pipeA[1]);
execvp(command2[0], command2);
printf("can not execute second command. \n");
exit(127);
}
int main(void)
{
//this variable will take in the line of input submitted by the user
char buf[1024];
//PIDs for the two child processes
pid_t pid;
pid_t pid2;
//these will be use to check the status of each child in the parent process
int status;
int status2;
//initializes the pipe
int pipeA[2];
//out put the first line to ask user for input
cout<< "480shel> ";
//stay inside the loop and keep asking the user for input until the user quits the program
while (fgets(buf,1024,stdin) != NULL){
//initialize a boolean to check if user wants to pipe something, set to false by default until we check with user
bool pipeExists = false;
//initialize this arrays to NULL so anything that store in them gets cleared out.
//these arrays will hold the commands that the user wants to carry out.
char * command[1024] = {NULL, NULL, NULL};
char * command2[1024] = {NULL, NULL, NULL};
//Important to delete mark the last byte as 0 in our input
buf[strlen(buf) -1] = 0;
//initialize this number to zero to start save the tokens at this index
int index = 0;
//a char * to hold the token saved by strtok
char * ptr;
ptr = strtok(buf, " ");
//Loop through 'buf' and save tokens accordingly
while(ptr != NULL){
//If ptr is equal to q or quit then user want to exit program
if(strcmp( ptr, "q" ) == 0){
exit(0);
}
if(strcmp( ptr, "quit" ) == 0){
exit(0);
}
//if ptr is equal to || user wants to pipe something and we change pipeExists to true
if(strcmp( ptr, "||" ) == 0){
pipeExists = true;
index= 0;
ptr = strtok(NULL, " ");
}
//enter here while user doesnt want to user pipes
if(!pipeExists){
command[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
//enter here if user want to use pipes
if(pipeExists){
command2[index] = ptr;
ptr = strtok(NULL, " ");
index++;
}
}
//if pipes exists then initialize it
if(pipeExists){
pipe(pipeA);
}
//create first child
if ((pid = fork()) == 0) {
//pass in the pipe, commands and pipe to function to execute
first_command(pipeA, command, pipeExists);
}
else if(pid < 0){
//error with child
cerr<<"error forking first child"<<endl;
}
// if pipe exists create a second process to execute the second part of the command
if(pipeExists){
//create second child
if ((pid2 = fork()) == 0) {
second_command(pipeA, command2);
}
else if(pid2 < 0){
//error with second child
cerr<<"error forking second child"<<endl;
}
}
//if the pipe was created then we close its ends
if(pipeExists){
close(pipeA[0]);
close(pipeA[1]);
}
//wait for the first child that ALWAYS executes
if ( (pid = waitpid(pid, &status, 0)) < 0)
cerr<<"error waiting for first child"<<endl;
//wait for the second child bu only if user wanted to created to use piping
if(pipeExists){
if ( (pid2 = waitpid(pid2, &status2, 0)) < 0)
cerr<<"error waiting for second child"<<endl;
}
cerr<<"480shell> ";
}//endwhile
exit(0);
}
I have this code in an example for my class, and the instructions from the teacher say to "make each thread loop for 5 iterations". I am confused as to how to do that, wtih this code:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <sys/utsname.h>
/* Symbolic Constants*/
#define NUM_THREADS 4
#define BUFFER_SIZE 10
/* Semaphore and Mutex lock */
sem_t cEmpty;
sem_t cFull;
pthread_mutex_t mutex;
/* Threads */
pthread_t tid; /* Thread ID */
pthread_attr_t attr; /* Thread attributes */
//prototypes
void *producer(void *param);
void *consumer(void *param);
int insert_item(int threadID);
int remove_item(int threadID);
void init();
/* Progress Counter and Thread IDs*/
int counter, pthreadID=0, cthreadID=0;
int main()
{
/* Variables */
int c1;
/* Perform initialization */
init();
/* Create the producer threads */
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid, &attr, producer, NULL);
}
/* Create the consumer threads */
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid, &attr, consumer, NULL);
}
/* Ending it */
sleep(2);
printf("All threads are done.\n");
/* Destroy the mutex and semaphors */
pthread_mutex_destroy(&mutex);
sem_destroy(&cEmpty);
sem_destroy(&cFull);
printf("Resources cleaned up.\n");
exit(0);
}
void init()
{
pthread_mutex_init(&mutex, NULL); /* Initialize mutex lock */
pthread_attr_init(&attr); /* Initialize pthread attributes to default */
sem_init(&cFull, 0, 0); /* Initialize full semaphore */
sem_init(&cEmpty, 0, BUFFER_SIZE); /* Initialize empty semaphore */
counter = 0; /* Initialize global counter */
}
void *producer(void *param)
{
int x;
for(x=0; x<5;)
{
sleep(1);
sem_wait(&cEmpty); /* Lock empty semaphore if not zero */
pthread_mutex_lock(&mutex);
if(insert_item(pthreadID))
{
fprintf(stderr, "Producer error.");
}
else
{
pthreadID++;
x++;
}
pthread_mutex_unlock(&mutex);
sem_post(&cFull); /* Increment semaphore for # of full */
}
return 0;
}
void *consumer(void *param)
{
int y;
for(y=0; y<5;)
{
sleep(1);
sem_wait(&cFull); /* Lock empty semaphore if not zero */
pthread_mutex_lock(&mutex);
if(remove_item(cthreadID))
{
fprintf(stderr, "Consumer error.");
}
else
{
cthreadID++;
y++;
}
pthread_mutex_unlock(&mutex);
sem_post(&cEmpty); /* Increments semaphore for # of empty */
}
return 0;
}
int insert_item(int threadID)
{
if(counter < BUFFER_SIZE) /* Buffer has space */
{
counter++;
printf("Producer %d inserted a cookie. Total:%d\n", threadID, counter);
return 0;
}
else /* Buffer full */
{
return -1;
}
}
int remove_item(int threadID)
{
if(counter > 0) /* Buffer has something in it */
{
counter--;
printf("Consumer %d removed a cookie. Total:%d\n", threadID, counter);
return 0;
}
else /* Buffer empty */
{
return -1;
}
}
Anyone have any idea of where I add my for loop to "make each thread loop for 5 iterations"? Thank you so much in advanced.
UPDATE: I changed the while(1) to a for loop with 5 iterations, but I still cant get the messages from the insert_item and remove_item functions to print 5 times, the only print once. Anyone know how I can get it to print 5 times?
The problem was that at the end of main, I call sleep(2). This is not enough time for all of the threads to print their output. I was also not passing the right index to my add_item and remove_item functions. In addition, I needed a join command for all of the threads rather than the sleep command, and the join command ensures that all of the threads finish before the program exits. Here is the updated and corrected code. Hope this helps someone trying to do something similar!
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <sys/utsname.h>
// Symbolic Constants
#define NUM_THREADS 4
#define BUFFER_SIZE 10
// Semaphore and Mutex lock
sem_t cEmpty;
sem_t cFull;
pthread_mutex_t mutex;
// Threads
pthread_t tid[NUM_THREADS]; //Thread ID
pthread_t tid2[NUM_THREADS]; //Thread ID
pthread_attr_t attr; //Thread attributes
//prototypes
void *producer(void *param);
void *consumer(void *param);
int insert_item(long threadID);
int remove_item(long threadID);
void init();
//Progress Counter and Thread IDs
int counter=0;
int main()
{
//Variables
long c1;
//Perform initialization
init();
//Create the producer threads
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_create(&tid[c1], &attr, producer, (void *)c1);
pthread_create(&tid2[c1], &attr, consumer, (void *)c1);
}
//Ending it
for(c1=0; c1<NUM_THREADS; c1++)
{
pthread_join(tid[c1], NULL);
pthread_join(tid2[c1],NULL);
}
printf("All threads are done.\n");
//Destroy the mutex and semaphors
pthread_mutex_destroy(&mutex);
sem_destroy(&cEmpty);
sem_destroy(&cFull);
printf("Resources cleaned up.\n");
exit(0);
}
//This function performs initialization
void init()
{
pthread_mutex_init(&mutex, NULL); //Initialize mutex lock
pthread_attr_init(&attr); //Initialize pthread attributes to default
sem_init(&cFull, 0, 0); //Initialize full semaphore
sem_init(&cEmpty, 0, BUFFER_SIZE); //Initialize empty semaphore
counter = 0; //Initialize global counter
}
//This function creates the producer thread
void *producer(void *param)
{
long index = (long)param;
for(int x = 0; x<5; x++)
{
sleep(1);
sem_wait(&cEmpty); //Lock empty semaphore if not zero
pthread_mutex_lock(&mutex);
//check to see if item inserted correctly; print error on fail
if(insert_item(index))
{
fprintf(stderr, "Producer error.");
}
pthread_mutex_unlock(&mutex);
sem_post(&cFull); //Increment semaphore for # of full
}
pthread_exit(NULL);
return 0;
}
//This function created the consumer thread
void *consumer(void *param)
{
long index = (long)param;
for(int x = 0; x<5; x++)
{
sleep(1);
sem_wait(&cFull); //Lock empty semaphore if not zero
pthread_mutex_lock(&mutex);
//print error if cookie not decremented correctly
if(remove_item(index))
{
fprintf(stderr, "Consumer error.");
}
pthread_mutex_unlock(&mutex);
sem_post(&cEmpty); //Increments semaphore for # of empty
}
pthread_exit(NULL);
return 0;
}
//Insert item function to increment the cookie count and print thread message
int insert_item(long threadID)
{
if(counter < BUFFER_SIZE) //Buffer has space
{
counter++;
printf("Producer %ld inserted a cookie. Total:%d\n", threadID, counter);
return 0;
}
else //Buffer full
{
return -1;
}
}
//Remove item function to decrement the cookie count and print thread message
int remove_item(long threadID)
{
if(counter > 0) //Buffer has something in it
{
counter--;
printf("Consumer %ld removed a cookie. Total:%d\n", threadID, counter);
return 0;
}
else //Buffer empty
{
return -1;
}
}