This question already has answers here:
c++ multiple definitions of a variable
(5 answers)
multiple definition error c++
(2 answers)
What exactly is One Definition Rule in C++?
(1 answer)
Closed 2 years ago.
I am attempting to compile my c++ code, and I continue getting the error:
/tmp/ccEsZppG.o:(.bss+0x0): multiple definition of `mailboxes'
/tmp/ccEZq43v.o:(.bss+0x0): first defined here
/tmp/ccEsZppG.o:(.bss+0xc0): multiple definition of `threads'
/tmp/ccEZq43v.o:(.bss+0xc0): first defined here
/tmp/ccEsZppG.o:(.bss+0x120): multiple definition of `semaphores'
/tmp/ccEZq43v.o:(.bss+0x120): first defined here
collect2: error: ld returned 1 exit status
Here is my code:
addem.cpp
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include "mailbox.h"
using namespace std;
void *sumUp(void *arg);
int main(int argc, char *argv[]) {
int numThreads, minThreads, maxInt, minInt;
if (argc < 3) {
cout << "Error: Need three arguments" << endl;
return 1;
}
numThreads = atoi(argv[1]);
maxInt = atoi(argv[2]);
minThreads = 1;
minInt = 1;
if (numThreads < 1) {
cout << "Cannot work with less than one thread\n"
<< "It's okay but do better next time!\n"
<< "We'll work with 1 thread this time.\n";
numThreads = minThreads;
} else if (numThreads > MAXTHREAD) {
cout << "Sorry, the max for threads is 10.\n"
<< "We'll work with 10 threads this time.\n";
numThreads = MAXTHREAD;
}
if (maxInt < 1) {
cout << "What do you want me to do? I can't count backwards!\n"
<< "I can barely count forwards! Let's make the max number\n"
<< "be 1 to save time\n";
maxInt = minInt;
}
struct msg outgoingMail[numThreads];
int divider = maxInt / numThreads;
int count = 1;
//initialize arrays (mailboxes, semaphores)
for (int i = 0; i < numThreads; i++) {
sem_init(&semaphores[i], 0, 1);
outgoingMail[i].iSender = 0;
outgoingMail[i].type = RANGE;
outgoingMail[i].value1 = count;
count = count + divider;
if (i = numThreads - 1) {
outgoingMail[i].value2 = maxInt;
} else {
outgoingMail[i].value2 = count;
}
}
for (int message = 0; message < numThreads; message++) {
SendMsg(message+1, outgoingMail[message]);
}
int thread;
for (thread = 0; thread <= numThreads; thread++) {
pthread_create(&threads[thread], NULL, &sumUp, (void *)(intptr_t)(thread+1));
}
struct msg incomingMsg;
int total = 0;
for (thread = 0; thread < numThreads; thread++) {
RecvMsg(0, incomingMsg);
total = total + incomingMsg.value1;
}
cout << "The total for 1 to " << maxInt << " using "
<< numThreads << " threads is " << total << endl;
return 0;
}
void *sumUp(void *arg) {
int index,total;
index = (intptr_t)arg;
struct msg message;
RecvMsg(index, message);
message.iSender = index;
message.type = ALLDONE;
total = 0;
for (int i = message.value1; i <= message.value2; i++) {
total += i;
}
SendMsg(0, message);
return (void *) 0;
}
mailbox.cpp
#include <stdio.h>
#include <iostream>
#include "mailbox.h"
using namespace std;
int SendMsg(int iTo, struct msg &Msg) {
if (safeToCall(iTo)) {
cout << "Error calling SendMsg" << endl;
return 1;
}
sem_wait(&semaphores[iTo]);
mailboxes[iTo] = Msg;
sem_post(&semaphores[iTo]);
return 0;
}
int RecvMsg(int iFrom, struct msg &Msg) {
sem_wait(&semaphores[iFrom]);
if (safeToCall(iFrom)) {
cout << "Error calling RecvMsg" << endl;
return 1;
}
mailboxes[iFrom] = Msg;
sem_post(&semaphores[iFrom]);
return 0;
}
bool safeToCall(int location) {
bool safe = !(location < 0 || location > MAXTHREAD + 1);
return safe;
//return true;
}
mailbox.h
#ifndef MAILBOX_H_
#define MAILBOX_H_
#define RANGE 1
#define ALLDONE 2
#define MAXTHREAD 10
#include <semaphore.h>
#include <pthread.h>
struct msg {
int iSender; /* sender of the message (0 .. numThreads)*/
int type; /* its type */
int value1; /* first value */
int value2; /* second value */
};
struct msg mailboxes[MAXTHREAD + 1];
pthread_t threads[MAXTHREAD + 1];
sem_t semaphores[MAXTHREAD + 1];
int SendMsg(int iTo, struct msg &Msg);
int RecvMsg(int iFrom, struct msg &Msg);
bool safeToCall(int location);
#endif
I am compiling the code with the command
g++ -o addem addem.cpp mailbox.cpp -lpthread
I have tried commenting out all of the function bodies in the source code to leave them as stub functions, and the same error occurs. The only way I have been able to compile the file is if I comment out the function bodies, and remove
#include "mailbox.h"
From at least one of the files. I feel it has to do with how I am initializing the arrays? But I cannot figure out a workaround.
Related
I would like to measure the maximum memory usage of abc.exe on random tests generated by gen.exe. How could I do that?
My code that runs abc.exe on tests from gen.exe looks like this:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i = 0;
while (true)
{
string si = to_string(i);
cout << i << "\n";
if (system(("echo " + si + "| ./gen.exe > test.in").c_str())) // gen.exe is test generator
{
cout << "gen error\n";
break;
}
if (system(("./abc.exe < test.in > a.out"))) // abc.exe is the program I want to test
{
cout << "abc error\n";
break;
}
i++;
}
}
I know that i can use time -v ./abc.exe but then the used memory is printed in the terminal but I'd like to be able to save it to a variable.
You can use getrusage( RUSAGE_CHILDREN, ... ) to obtain the maximum resident memory. Note that this call will return the maximum memory used by the biggest child at that point in time.
In the example below I used boost::process because it gives better control but it's up to you to use std::system or not, works the same way.
#include <string>
#include <cstdint>
#include <string.h>
#include <iostream>
#include <boost/process/child.hpp>
#include <sys/resource.h>
namespace bp = boost::process;
int parent( const std::string& exename )
{
// Loop from 0 to 10 megabytes
for ( int j=0; j<10; ++j )
{
// Command name is the name of this executable plus one argument with size
std::string gencmd = exename + " " + std::to_string(j);
// Start process
bp::child child( gencmd );
// Wait for it to allocate memory
sleep(1);
// Query the memory usage at this point in time
struct rusage ru;
getrusage( RUSAGE_CHILDREN, &ru );
std::cerr << "Loop:" << j << " mem:"<< ru.ru_maxrss/1024. << " MB" << std::endl;
// Wait for process to quit
child.wait();
if ( child.exit_code()!=0 )
{
std::cerr << "Error executing child:" << child.exit_code() << std::endl;
return 1;
}
}
return 0;
}
int child( int size ) {
// Allocated "size" megabites explicitly
size_t memsize = size*1024*1024;
uint8_t* ptr = (uint8_t*)malloc( memsize );
memset( ptr, size, memsize );
// Wait for the parent to sample our memory usage
sleep( 2 );
// Free memory
free( ptr );
return 0;
}
int main( int argc, char* argv[] )
{
// Without arguments, it is the parent.
// Pass the name of the binary
if ( argc==1 ) return parent( argv[0] );
return child( std::atoi( argv[1] ) );
}
It prints
$ ./env_test
Loop:0 mem:0 MB
Loop:1 mem:3.5625 MB
Loop:2 mem:4.01953 MB
Loop:3 mem:5.05469 MB
Loop:4 mem:6.04688 MB
Loop:5 mem:7.05078 MB
Loop:6 mem:7.78516 MB
Loop:7 mem:8.97266 MB
Loop:8 mem:9.82031 MB
Loop:9 mem:10.8867 MB
If you cannot use boost libraries, you'd got to work a little more but it is still feasible.
If you just want to know the maximum size ever of your children processes then the following works with std::system:
#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
int main(int argc, char* argv[]) {
if (argc > 1) {
size_t size = ::atol(argv[1]);
size_t memsize = size * 1024 * 1024;
void* ptr = ::malloc(memsize);
memset(ptr, 0, memsize);
::sleep(2);
::free(ptr);
return 0;
}
for (int j = 0; j < 10; ++j) {
std::ostringstream cmd;
cmd << argv[0] << " " << j;
int res = std::system(cmd.str().c_str());
if (res < 0) {
fprintf(stderr, "ERROR system: %s\n", strerror(errno));
break;
}
struct rusage ru;
res = getrusage(RUSAGE_CHILDREN, &ru);
size_t maxmem = ru.ru_maxrss;
fprintf(stderr, "Loop:%d MaxMem:%ld\n", j, maxmem);
}
return 0;
}
It prints
Loop:0 MaxMem:3552
Loop:1 MaxMem:4192
Loop:2 MaxMem:5148
Loop:3 MaxMem:6228
Loop:4 MaxMem:7364
Loop:5 MaxMem:8456
Loop:6 MaxMem:9120
Loop:7 MaxMem:10188
Loop:8 MaxMem:11324
Loop:9 MaxMem:12256
However if you want to keep track of the memory usage during the child process execution you cannot use std::system(). First, you need to call fork() to spawn a new process and then execv() to execute a bash command.
#include <string>
#include <cstdint>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <sys/resource.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <vector>
int parent(const std::string& exename) {
// Loop from 0 to 10 megabytes
for (int j = 0; j < 10; ++j) {
// Command name is the name of this executable plus one argument with size
std::string gencmd = exename + " " + std::to_string(j);
// Start process
pid_t pid = fork();
if (pid == 0) { // child
const char* args[] = {"/bin/bash", "-c", gencmd.c_str(), (char*)0};
int res = execv("/bin/bash", (char**)args);
// Should never return
std::cerr << "execv error: " << strerror(errno) << std::endl;
return 1;
}
// parent
long maxmem = 0;
while (true) {
int status;
pid_t rid = ::waitpid(pid, &status, WNOHANG);
if (rid < 0) {
if (errno != ECHILD) {
std::cerr << "waitpid:" << strerror(errno) << std::endl;
return 2;
}
break;
}
if (rid == pid) {
if (WIFEXITED(pid)) {
break;
}
}
// Wait for it to allocate memory
usleep(10000);
// Query the memory usage at this point in time
struct rusage ru;
int res = getrusage(RUSAGE_CHILDREN, &ru);
if (res != 0) {
if (errno != ECHILD) {
std::cerr << "getrusage:" << errno << strerror(errno) << std::endl;
}
break;
}
if (maxmem < ru.ru_maxrss) {
maxmem = ru.ru_maxrss;
}
}
std::cerr << "Loop:" << j << " mem:" << maxmem / 1024. << " MB" << std::endl;
}
return 0;
}
int child(int size) {
// Allocated "size" megabites explicitly
size_t memsize = size * 1024 * 1024;
uint8_t* ptr = (uint8_t*)malloc(memsize);
memset(ptr, size, memsize);
// Wait for the parent to sample our memory usage
sleep(2);
// Free memory
free(ptr);
return 0;
}
int main(int argc, char* argv[]) {
// Without arguments, it is the parent.
// Pass the name of the binary
if (argc == 1) return parent(argv[0]);
return child(std::atoi(argv[1]));
}
The result on my machine is:
$ ./fork_test
Loop:0 mem:3.22656 MB
Loop:1 mem:3.69922 MB
Loop:2 mem:4.80859 MB
Loop:3 mem:5.92578 MB
Loop:4 mem:6.87109 MB
Loop:5 mem:8.05469 MB
Loop:6 mem:8.77344 MB
Loop:7 mem:9.71875 MB
Loop:8 mem:10.7422 MB
Loop:9 mem:11.6797 MB
There is a video about this post.
I am trying to create shared memory, but whenever I access it from a child process its value is different than what it should be. I think that I am using shmget() correctly. I have tried a lot of stuff that I have found online, but I can't find anyone with the same problem I am having. No matter what I enter num as, whenever I try to get l->returnLicense it outputs 0. I'm really at a loss as to what to try next.
#include "license.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <string>
#include <sys/wait.h>
#include <iostream>
#include <unistd.h>
using namespace std;
int validateArguments (int num) {
if (num == -69) {
//no arg
return 10;
}
if (num < 1 || num > 20) {
//warning use 20 as num
return 10;
}
return num;
}
int initSharedMemory (License *l) {
key_t key = ftok("/tmp", 'J');
cout << "key: " << key << endl;
int shmid = shmget(key, sizeof(l), 0666|IPC_CREAT);
if (shmid == -1) {
perror("Shared memory");
return -1;
}
l = (License*)shmat(shmid, (void*)0, 0);
if (l == (void*) -1) {
perror("Shared memory attach");
return -1;
}
return shmid;
}
void detachSharedMemory (License *l) {
shmdt(l);
}
void destroySharedMemory (int shmid) {
shmctl(shmid, IPC_RMID, NULL);
}
void spawn (int shmid) {
pid_t c_pid = fork();
if (c_pid == -1) {
perror("fork");
} else if (c_pid > 0) {
cout << "parent" << shmid << endl;
c_pid = wait(NULL);
} else {
cout << "child" << endl;
License *l;
key_t key = ftok("/tmp", 'J');
cout << "key: " << key << endl;
int shmid = shmget(key, sizeof(l), 0666);
cout << shmid;
l = (License*) shmat(shmid,0,0);
if(l == (void*) -1) {
perror("memory attach");
exit(0);
}
int num = l->returnLicense();
cout << num << "num\n";
shmdt(l);
char* args[] = {"./testChild", NULL};
execvp(args[0],args);
exit(0);
}
}
int main (int argv, char *argc[]) {
int num;
if (argv == 2) {
num = atoi(argc[1]);
} else {
num = -69;
}
num = validateArguments (num);
License *l;
int shmid = initSharedMemory (l);
License *tmp = l;
tmp->initLicense(num);
spawn(shmid);
cout << l->returnLicense() << endl;
detachSharedMemory(l);
destroySharedMemory(shmid);
return 0;
}
I'm not including the entirety of my code, but I think this is enough to illustrate my problem. I copied code from the testChild that I exec from this process so that you can see the problem I'm facing all in one file.
License *l; // uninitialized
int shmid = initSharedMemory (l); // pass l by value, UB!
License *tmp = l; // copy uninitialized pointer, UB!
tmp->initLicense(num); // call member function through uninitialized pointer, BOOM!
spawn(shmid);
cout << l->returnLicense() << endl; // call member function through uninitialized pointer, BOOM!
Probably you meant for your initSharedMemory() function to have a reference-typed parameter, so that it would affect the License * l; variable in main().
I have following piece of code :
// temp.h
#include <iostream>
#include <pthread.h>
static pthread_spinlock_t mylock;
__attribute__((constructor))
void init_lock() {
if(pthread_spin_init(&my_lock,0) != 0) {
// hard exit !!
exit(1);
}
}
__attribute__((destructor))
void uninit_lock() {
if(pthread_spin_destroy(&my_lock) != 0) {
// hard exit !!
exit(1);
}
}
#define EXPAND_VAR(ARG1, ARG2) \
do {\
assert(pthread_spin_lock(&my_lock) == 0);
/// do something
assert(pthread_spin_unlock(&my_lock) == 0);\
}while(0)
// main.cpp
#include "temp.h"
#define NUM_THREADS 5
void *logs(void *i){
int j;
for(j = 0 ; j < 10000 ; j++){
EXPAND_VAR(j, j+1);
}
std::cout << "returning from thread func" << std::endl;
pthread_exit(NULL);
}
int main(int argc, char* argv[]) {
int i;
pthread_t threads[NUM_THREADS];
for( i = 0; i < NUM_THREADS; i++) {
std::cout << " creating threads" << std::endl;
rc = pthread_create(&threads[i],NULL,logs,(void *)i);
}
std::cout << "returning from main" << std::endl;
pthread_exit(NULL);
return 0;
}
When executing the above code 'pthread_spin_lock' always gets blocked. I tried 'pthread_spin_trylock' and it passes with return value 0.
Anything i am missing that 'pthread_spin_lock' not working ?
I am using gcc version 4.1.2 :(
I am having a bit of trouble getting a System V Message Queue setup and working properly on Linux. The idea is to get a central node to pull data from several other nodes. The trouble is that the central node ends up sitting there waiting for the other nodes to send messages. I have looked at the values for the mailboxes and they are the same across all processes. I.E. 0 for the central mailbox, 32769 for other process 1, ect. I have no idea on why it appears to fail. I have tried to change the priority parameter in msgrcv to 0 to accept all incoming messages and the same issue occurs. Any help would be much appriciated. (Sorry for the lack of comments.)
Here is the code for the central node:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <iostream>
struct{
long priority;
int temperature;
int pid;
int stable;
} msgp;
const int mainMailID = 8484;
using namespace std;
int main(int argc, char* argv[]){
//declare needed variables
int centralMailID;
int externalMailID[4];
int tempdata;
int externalTempature[4];
int externalTemperatureLast[4];
//set initial values for msgp
msgp.priority = 2;
msgp.temperature = atoi(argv[1]);
msgp.pid = 0;
msgp.stable = 0;
//create the central mailbox
centralMailID = msgget(mainMailID, 0600 | IPC_CREAT);
if(centralMailID == -1){
cout << "Message Queue Creation Failed" << endl;
}
else{
cout << "Message Queue Created" << endl;
}
//create the external mailboxes
for(int i = 0; i < 4 ; i++){
externalMailID[i] = msgget(mainMailID + i+1, 0600 | IPC_CREAT);
if(externalMailID[i] == -1){
cout << "Message Queue " << i << " Creation Failed" << endl;
}
else{
cout << "Message Queue " << i << " Created" << endl;
}
}
printf("%i", externalMailID[0]);
while(msgp.stable == 0){
int centralTemperature = msgp.temperature;
//get the tempatures from the external sensors.
for(int i = 0; i<4; i++){
tempdata = msgrcv(externalMailID[i], &msgp, sizeof(msgp)-sizeof(long), 2, 0);
cout << "Recived data from sensor " << msgp.pid << endl;
externalTempature[i] = msgp.temperature;
}
if(externalTempature[0] == externalTempature[1] == externalTempature[2] == externalTempature[3] == centralTemperature){
msgp.stable = 1;
continue; //could also use break
}
int sum = 0;
for(int i = 0; i<4; i++){
sum = sum + externalTempature[i];
}
centralTemperature = ((2 * centralTemperature) + sum)/6;
msgp.temperature = centralTemperature;
for(int i = 0; i<4; i++){
tempdata = msgsnd(externalMailID[i], &msgp, sizeof(msgp)-sizeof(long), 0);
printf("Sent data to external mailbox %i", i);
}
}
printf("Process ended");
return 0;
}
Here is the code for the other nodes:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <iostream>
struct{
long priority;
int temperature;
int pid;
int stable;
} msgp;
const int mainMailID = 8484;
using namespace std;
int main(int argc, char* argv[]){
int centralMailID = msgget(mainMailID, 0600 | IPC_CREAT);
int pid = atoi(argv[2]);
int externalMailID = msgget(mainMailID + pid, 0600 | IPC_CREAT);
int externalTemperature = atoi(argv[1]);
int tempdata;
cout << externalMailID << endl;
msgp.priority = 2;
msgp.pid = pid;
msgp.stable = 0;
while(msgp.stable == 0){
msgp.temperature = externalTemperature;
tempdata = msgsnd(centralMailID, &msgp, sizeof(msgp)-sizeof(long), 0);
tempdata = msgrcv(externalMailID, &msgp, sizeof(msgp)-sizeof(long), 2, 0);
externalTemperature = ((externalTemperature * 3) + (msgp.temperature * 2))/5;
if(msgp.stable == 1){
continue;
}
}
printf("Child Process Ended");
return 0;
}
You're using the system V api, which is probably not what you want. See here for more details:
http://mij.oltrelinux.com/devel/unixprg/#ipc__posix_msgqs
The msgget, msgctl, msgsnd, msgrcv commands are part of the older, system V api, and while the semantics are similar, are not posix queues. A couple of quick google search for system V queue tutorials/examples are likely to solve your problem.
If you're genuinely looking to use posix queues, switch to and look for documentation on the mq_open, mq_close, mq_unlink, mq_send, mq_receive, mq_getattr, mq_setattr api.
I'm working on a Producer Consumer (Multithreaded) problem and I'm encountering a deadlock. My question is how?
I have multiple producers creating n products, and putting them in a global queue. The producers must WAIT if there is no room in the queue.
My consumers are accessing the queue by using First Come First Serve. The consumer must WAIT if there is nothing in the queue. The consumer will consume PART of the product, and the product will only be removed from the queue when it has been totally consumed. The consumers will stop consuming when there are no more products to be consumed.
I get the deadlock when the first item is done being consumed. I am using a mutex to lock the queue, 2 condition variables to signal when an item is added or removed to the queue, and a semaphore to keep track of total items being consumed.
Any idea why it may be deadlocking?
Input: 2 (Producers) 3 (Consumers) 5 (Items to produce) 2 (Queue Size) 0 (N/A) 50 (Quantum) 1 (Seed)
Producer:
#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"
#include <iostream>
#include <sys/time.h>
void* producer(void* args)
{
tProducer producer = *((tProducer*) args);
tProduct products[producer.products];
unsigned int queueMax = producer.queueMax;
timeval time;
std::string output;
for(int i = 0; i < producer.products; i++)
{
//Create item
products[i].productId = i;
products[i].life = producer.lifeOfProduct;
gettimeofday(&time, NULL);
products[i].timestamp = time.tv_sec;
//Lock and add to queue
pthread_mutex_lock(&queueLock);
//Queue is full and must wait
if(queue.size() >= queueMax)
{
output = "Producer: " + std::to_string(producer.id) + " is waiting\n";
std::cout << output;
pthread_cond_wait(&removeSignal, &queueLock);
}
//Debug message
output = "Producer: " + std::to_string(producer.id) + " is producing.\n";
std::cout << output;
//Add item to queue and signal
queue.push(products[i]);
pthread_cond_signal(&addSignal);
pthread_mutex_unlock(&queueLock);
//pthread_cond_signal(&addSignal);
//Debug message
output = "Producer: " + std::to_string(producer.id) + " just produced.\n";
std::cout << output;
}
pthread_exit(NULL);
}
Consumer:
#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"
#include <iostream>
void* consumer(void* args)
{
tConsumer consumer = *((tConsumer*) args);
int id = consumer.id;
int quantum = consumer.quantum;
std::string output;
while(true)
{
//Exit when nothing else is being created
if(sem_trywait(&totalProductsLeft) < 0)
{
break;
}
//Subtract life from product, and remove from queue if done
pthread_mutex_lock(&queueLock);
//Wait until item is in queue
if(queue.size() <= 0)
{
//Debug message
output = "Consumer: " + std::to_string(id) + " is waiting.\n";
std::cout << output;
pthread_cond_wait(&addSignal, &queueLock);
}
//Debug message
output = "Consumer: " + std::to_string(id) + " is ready.\n";
std::cout << output;
tProduct& product = queue.front();
product.life -= quantum;
//Item is done being consumed
if(product.life <= 0)
{
//Debug message
output = "Product: " + std::to_string(product.productId) + " is dead.\n";
std::cout << output;
//Remove a spot
queue.pop();
pthread_cond_signal(&removeSignal);
sem_wait(&totalProductsLeft);
}
else
{
//Debug message
output = "Product: " + std::to_string(product.life) + "hp is not done.\n";
std::cout << output;
}
pthread_mutex_unlock(&queueLock);
}
//May need to broadcast
pthread_exit(NULL);
}
Main (Just to show how I initialize everything):
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <pthread.h>
#include <semaphore.h>
#include "producerConsumer.h"
std::queue<tProduct> queue;
pthread_cond_t addSignal;
pthread_cond_t removeSignal;
sem_t totalProductsLeft;
pthread_mutex_t queueLock;
int main(int argc, char** argv)
{
//Handle input
const int NUM_INPUTS = 8;
int numberProducers;
int numberConsumers;
int numberOfProducts;
int queueSize;
int scheduleType;
int quantum;
int seed;
//Error check for input
if(argc != NUM_INPUTS)
{
std::cout << "Invalid number of arguments.\n";
return -1;
}
//Grab arguments
numberProducers = atoi(argv[1]);
numberConsumers = atoi(argv[2]);
numberOfProducts = atoi(argv[3]);
queueSize = atoi(argv[4]);
scheduleType = atoi(argv[5]);
quantum = atoi(argv[6]);
seed = atoi(argv[7]);
//Get rid of warnings for now
std::cout << numberOfProducts << std::endl;
std::cout << queueSize << std::endl;
std::cout << quantum << std::endl;
std::cout << seed << std::endl;
std::cout << scheduleType << std::endl;
//Create threads
pthread_t producerThreads[numberProducers];
pthread_t consumerThreads[numberConsumers];
tProducer producerArgs[numberProducers];
tConsumer consumerArgs[numberConsumers];
//Initialize global
pthread_mutex_init(&queueLock, NULL);
pthread_cond_init(&addSignal, NULL);
pthread_cond_init(&removeSignal, NULL);
std::cout << "Total Items: " << (numberProducers * numberOfProducts) << std::endl;
sem_init(&totalProductsLeft, 0, numberProducers * numberOfProducts);
//Start threads
srand(seed);
for(int i = 0; i < numberProducers; i++)
{
producerArgs[i].id = i;
producerArgs[i].products = numberOfProducts;
producerArgs[i].lifeOfProduct = rand() % 1024;
producerArgs[i].queueMax = queueSize;
pthread_create(&(producerThreads[i]), 0, producer, &producerArgs[i]);
}
for(int i = 0; i < numberConsumers; i++)
{
consumerArgs[i].id = i;
consumerArgs[i].quantum = quantum;
pthread_create(&(consumerThreads[i]), 0, consumer, &consumerArgs[i]);
}
//Wait for threads to end
for(int i = 0; i < numberProducers; i++)
{
pthread_join(producerThreads[i], NULL);
}
for(int i = 0; i < numberConsumers; i++)
{
pthread_join(consumerThreads[i], NULL);
}
return 0;
}
I ended up figuring it out. sem_trywait, in my consumer, is decrementing when items weren't done being consumed. The sem_wait inside my consumer is then blocking because there are no items left.