naming threads, using typedef/struct - c++

I am creating a program to practice using threads. I am trying to name them so that when the program is run, you can clearly see "Flight 1 is taking off..." or "Flight 6 is landing..." and so on. I would like every thread to have a flyTime (so I know what order they will use the runway in) which will be randomly generated. I have tried and am having difficulty using struct/typedef to give each pthread these characteristics so i can say for example flight.flyTime and use it throughout the program. Here is the relevant part of my code without my landing/takeoff functions:
#include <pthread.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <queue>
#define NUM_THREADS 8 //8 flights
pthread_mutex_t runway1lock;
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
pthread_exit(NULL);
}
typedef struct{ //each plane has these characteristics
long fid;
int StartState; // if start=1 ==> taking off:::if start=2 ==> landing
int flyTime; //fly == randomly generated time (order)
}FLIGHTS;
FLIGHTS flights[NUM_THREADS];
int StartState(flights[NUM_THREADS]){
int startState;
for (int i=0; i<=NUM_THREADS; i++){
startState = rand() % 1+2;
}
std::string start;
if(startState == 1){
start = "Taking off";
}
if(startState == 2){
start = "Landing";
}
for (int t=0; t<NUM_THREADS; t++){
std::cout << "Start State for Flight# " << FlightID << " is " << start << std::endl;
}
return startState;
}
int main(int argc, char *argv[]){
// pthread_t flights[NUM_THREADS]; //pthread_t keeps a thread ID after the thread is created with pthread_create()
//it's like an index on a vector of threads
int rc;
long t;
for (t=1; t<=NUM_THREADS; t++){ //loop creates threads(flights)
printf("In main: Creating flight %1d\n", t);
rc = pthread_create(&flights[t], NULL, FlightID, (void *)t);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
StartState(flights[t]); //gives every flight a start state
if(StartState(flights[t])==1){
std::cout << "Flight # " << &flights[t] << " is listed as waiting at the gate." << std::endl;
//go to takeoff function and go through switch case
}
if(StartState(flights[t])==2){`enter code here`
std::cout << "Flight # " << &flights[t] << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
}
pthread_exit(NULL);
}

There is a code snippet below that represents how I would implement it.
You should also take a look at pthread_key_create, pthread_getspecific and pthread_setspecific. This is a set of functions that allow you to have data, specific to each thread, stored in the thread's memory context. It may come in handy for in your code, later on.
typedef struct{
long fid;
int StartState;
int flyTime;
} FLIGHTS;
FLIGHTS** flights = new FLIGHTS*[NUM_THREADS];
pthread_key_t pkey:
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
FLIGHTS* flight = new FLIGHTS();
flight->fid = fid;
flights[fid] = flight;
pthread_setspecific(pkey, flight);
int startState;
for (int i=0; i<=NUM_THREADS; i++){
startState = rand() % 1+2;
}
std::string start;
if(startState == 1){
start = "Taking off";
}
if(startState == 2){
start = "Landing";
}
for (int t=0; t<NUM_THREADS; t++){
std::cout << "Start State for Flight# " << fid << " is " << start << std::endl;
}
flight->StartState = startState;
}
int main(int argc, char* argv[]) {
pthread_key_create(&pkey, NULL);
for (t=1; t<=NUM_THREADS; t++){
rc = pthread_create(&flights[t], NULL, FlightID, (void *)t);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
}
}
Also, I don't know if I'm understanding your code correctly or if you just have some coding errors on it, so I leave you with some questions or remarks that could be mistakes/bugs:
1) You invoke pthread_exit in the start callback function:
void *FlightID(void *flightid){
long fid;
fid = (long)flightid;
pthread_exit(NULL);
}
2) You pass to the << operator a function with no return value:
std::cout << "Start State for Flight# " << FlightID << " is " << start << std::endl;
3) You invoke the same function 3 times just to get the return value. Shouldn't it be int state = StartState(flights[i]) and then test the state variable value?
StartState(flights[t]); //gives every flight a start state
if(StartState(flights[t])==1){
std::cout << "Flight # " << &flights[t] << " is listed as waiting at the gate." << std::endl;
//go to takeoff function and go through switch case
}
if(StartState(flights[t])==2){`enter code here`
std::cout << "Flight # " << &flights[t] << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
4) You can't define a function like this:
int StartState(flights[NUM_THREADS]){

Related

Interrupt and, if necessary, terminate a program at regular intervals in c++

I need your help. Program A executes program B with fork(). Every 5 seconds the process belonging to program B is interrupted. If the user enters any key within a certain time, the process is continued and interrupted again after the same time interval. If no key is entered, both program A and program B are terminated prematurely. I have tried the following code, but it does not work. Any suggestions/tips that will help me?
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
using namespace std;
using namespace chrono;
int pid;
void signal_handler(int signum) {
cout << "Programm B is interrupted. Please enter any key within 5 or the programm will be terminated" << endl;
kill(pid,SIGSTOP);
alarm(5);
pause();
alarm(5);
}
int main(int argc, char* argv[]) {
//Usage
if(string(argv[1]) == "h" || string(argv[1]) == "help"){
cout << "usage" << endl;
return 0;
}
signal(SIGALRM, signal_handler);
pid = fork();
if (pid == 0) {
cout << "Name of programm B: " << argv[1] << endl;
cout << "PID of programm B: " << getpid() << endl;
execvp(argv[1], &argv[1]);
} else if (pid > 0) {
cout << "PID of programm A: " << getpid() << endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
waitpid(pid, nullptr, 0);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t2 - t1).count();
cout << "Computing time: " << duration << "ms" << endl;
} else {
cerr << "error << endl;
return 1;
}
return 0;
}
Any help or sulution. I am a beginner in c++ btw.
Signals can get tricky and there are lots of issues with your approach.
You should:
kick off the timer (alarm(5)) in main
do the sighandler registration and timer kick-off after you've spawned the child (or you somewhat risk running the signal handler in the child in between fork and execvp)
use sigaction rather than signal to register the signal, as the former has clear portable semantics unlike the latter
loop on EINTR around waitpid (as signal interruptions will cause waitpid to fail with EINTR)
As for the handler, it'll need to
use only async-signal-safe functions
register another alarm() around read
unblock SIGALRM for the alarm around read but not before you somehow mark yourself as being in your SIGALRM signal handler already so the potential recursive entry of the handler can do a different thing (kill the child and exit)
(For the last point, you could do without signal-unblocking if you register the handler with .sa_flags = SA_NODEFER, but that has the downside of opening up your application to stack-overflow caused by many externally sent (via kill) SIGALRMs. If you wanted to handle externally sent SIGALRMs precisely, you could register the handler with .sa_flags=SA_SIGINFO and use info->si_code to differentiate between user-sends and alarm-sends of SIGALRM, presumably aborting on externally-sent ones)
It could look something like this (based on your code):
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
//AS-safe raw io helper functions
ssize_t /* Write "n" bytes to a descriptor */
writen(int fd, const char *ptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) < 0) {
if (nleft == n)
return(-1); /* error, return -1 */
else
break; /* error, return amount written so far */
} else if (nwritten == 0) {
break;
}
nleft -= nwritten;
ptr += nwritten;
}
return(n - nleft); /* return >= 0 */
}
ssize_t writes(int fd, char const *str0) { return writen(fd,str0,strlen(str0)); }
ssize_t writes2(char const *str0) { return writes(2,str0); }
//AS-safe sigprockmask helpers (they're in libc too, but not specified as AS-safe)
int sigrelse(int sig){
sigset_t set; sigemptyset(&set); sigaddset(&set,sig);
return sigprocmask(SIG_UNBLOCK,&set,0);
}
int sighold(int sig){
sigset_t set; sigemptyset(&set); sigaddset(&set,sig);
return sigprocmask(SIG_BLOCK,&set,0);
}
#define INTERRUPT_TIME 5
using namespace std;
using namespace chrono;
int pid;
volatile sig_atomic_t recursing_handler_eh; //to differentiate recursive executions of signal_handler
void signal_handler(int signum) {
char ch;
if(!recursing_handler_eh){
kill(pid,SIGSTOP);
writes2("Programm B is interrupted. Please type enter within 5 seconds or the programm will be terminated\n");
alarm(5);
recursing_handler_eh = 1;
sigrelse(SIGALRM);
if (1!=read(0,&ch,1)) signal_handler(signum);
alarm(0);
sighold(SIGALRM);
writes2("Continuing");
kill(pid,SIGCONT);
recursing_handler_eh=0;
alarm(INTERRUPT_TIME);
return;
}
kill(pid,SIGTERM);
_exit(1);
}
int main(int argc, char* argv[]) {
//Usage
if(string(argv[1]) == "h" || string(argv[1]) == "help"){
cout << "usage" << endl;
return 0;
}
pid = fork();
if (pid == 0) {
cout << "Name of programm B: " << argv[1] << endl;
cout << "PID of programm B: " << getpid() << endl;
execvp(argv[1], &argv[1]);
} else if (pid < 0) { cerr << "error" <<endl; return 1; }
struct sigaction sa; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags=0; sigaction(SIGALRM, &sa,0);
//signal(SIGALRM, signal_handler);
alarm(INTERRUPT_TIME);
cout << "PID of programm A: " << getpid() << endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
int r;
do r = waitpid(pid, nullptr, 0); while(r==-1 && errno==EINTR);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t2 - t1).count();
cout << "Computing time: " << duration << "ms" << endl;
return 0;
}
Not that the above will wait only for an enter key. To wait for any key, you'll need to put your terminal in raw/cbreak mode and restore the previous settings on exit (ideally on signal deaths too).

How to do: when we press and hold, program just do once?

I am making a game console with C++, I have a problem. When I press SPACE, my car in my game will jump. When I press and hold keyboard, my car will jump many times. I want: when I hold SPACE keyboard my car just jump once.
How to do this ?
I have read many topics about GetAsyncKeyState() but I don't know how to use it for my game.
if ( _kbhit() )
{
char key = _getch();
if ((key == 75) && (car.position.x > 2))
{
car.position.x -= 3;
}
else if ((key == 77) && (car.position.x < 24))
{
car.position.x += 3;
}
else if ((key == 32) && (car.position.y > 2))
{
car.position.y -= 5;
}
}
Below I have an example software of one possible way to 'filter' duplicate space chars out of an input stream.
The idea relies on the use of two threads.
Thrd1 reads from a stringstream called ssIn. (Replaced with cin in your code.)
Thrd1 (a filter) detects and discards back-to-back space chars, and only sends the first (of multiple space chars) to thrd2.
Thrd2 - reads from the single char buffer filled by thrd1 which will never see back-to-back space characters.
The 2 thrds are synchronized by a pair of semaphores (not mutex).
In my example, for my convenience, I used my version of a Posix semaphore. I do not know if you have Posix, but I am confident you will easily find many example C++ semaphores available on the web, even within SO, and most using only C++ features.
Note that this is only 1 test ... the alphabet with 1,000,000 spaces injected after 'j'. This is not a thourough test. There probably will be other issues to deal with. I have installed a harsh handling of input mis-behaviour. The assert will help you identify the issues.
"thrd2" represents your toe-hold into this example. Thrd2 receives the filtered stream.
#include "../../bag/src/dtb_chrono.hh"
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
using std::chrono::duration_cast;
#include <iostream>
using std::cout, std::flush, std::endl;
//using std::cin;
#include <thread>
using std::thread, std::this_thread::sleep_for;
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
// Posix Process Semaphore, local mode, unnamed, unlocked
#ifndef DTB_PPLSEM_HH
#include "../../bag/src/dtb_pplsem.hh"
using DTB::PPLSem_t;
#endif
// string ops
#ifndef DTB_SOPS_HH
#include "../../bag/src/dtb_sops.hh"
using DTB::SOps_t;
#endif
#include <cassert>
namespace DTB
{
class T946_t
{
public:
int operator()(int argc, char* argv[]) // functor entry
{ return exec(argc, argv); }
private:
// uses compiler provided default ctor and dtor
// Posix Process Semaphore, local mode (unnamed, unshared)
// initial value unlocked
PPLSem_t th1Sem;
PPLSem_t th2Sem;
char kar = '\n';
bool done = false;
size_t m_rdy;
thread* th1;
string th1Log;
thread* th2;
string th2Log;
stringstream ssIn; // debug - replaces cin
stringstream ss1DR; // th1 delay'd report
stringstream ss2DR; // th2 delay'd report
// utilities
SOps_t sops; // string ops - digiComma
int exec(int , char** )
{
// test init: insert a possible user input into ssIn
init_ssIn();
int retVal = 0;
Time_t start_ns = HRClk_t::now();
th1Sem.lock(); // block until threads are ready
th2Sem.lock(); // block
// start ---------vvvvvvvvvvvvvvvvvvv
th1 = new thread(&T946_t::thrd1, this);
assert(nullptr != th1);
while (0 == (m_rdy & 0x01))
std::this_thread::sleep_for(10ms);
// start ---------vvvvvvvvvvvvvvvvvv
th2 = new thread(&T946_t::thrd2, this);
assert(nullptr != th2);
while (0 == (m_rdy & 0x02))
std::this_thread::sleep_for(10ms);
th1Sem.unlock();
// spin wait for threads to complete
while (!done)
{
std::this_thread::sleep_for(100ms);
}
th1->join();
th2->join();
cout << "\n join()'s complete";
auto duration_ns = duration_cast<NS_t>(HRClk_t::now() - start_ns).count();
cout << "\n T901_t::exec() duration "
<< sops.digiComma(duration_ns) << " ns" << endl;
// output the delay'd reports
cout << ss1DR.str() << ss2DR.str() << endl;
return retVal;
}
void init_ssIn()
{
ssIn << "abcdefghij";
for (int i=0; i<1000001; ++i) ssIn << ' ';
std::string::size_type k = ssIn.str().size();
ssIn << "klmnopqrstuvwxyz";
// a..j
cout << "\n ssIn: '" << ssIn.str().substr(0, 10)
<< " ...spaces... " << ssIn.str().substr(k, 16) << "'"
<< "\n ssIn.str().size(): "
<< sops.digiComma(ssIn.str().size()) << endl;
}
void thrd1()
{
uint64_t th1Count = 0;
uint64_t th1Skips = 0;
char lkar = '\0';
m_rdy |= 0x01; // sync msg to main
do {
getNextKar(lkar); // read from input (ssIn or cin)
th1Sem.lock(); // wait for thrd2 to give permission
{
if(' ' == lkar) // current input kar
{
if(' ' == kar) // previous kar
{
// filter out back-to-back space chars
th1Skips += 1;
th1Sem.unlock(); // skip the handshake, no char to send,
// give self permission-to-proceed
continue;
}
}
// else, not a duplicate space
th1Count += 1;
kar = lkar; // write to input of thrd2
th1Log += lkar; // log
lkar = ' ';
}
th2Sem.unlock(); // give thrd2 permission-to-proceed
if (ssIn.eof())
{
done = true;
break;
}
}while(!done);
ss1DR
<< "\n th1Count " << sops.digiComma(th1Count)
<< "\n th1Skips " << sops.digiComma(th1Skips)
<< "\n th1Log " << th1Log
<< "\n thrd1 exit " << endl;
}
// read from ssIn for development
// read from cin for app
void getNextKar(char& lkar)
{
// ssIn >> lkar; // reads 1 char, but skips multiple blank chars
// lkar = ssIn.get(); returns an integer (not a char)
(void)ssIn.get (lkar);
if(ssIn.fail())
{
if(ssIn.eof()) return; // not a fail
assert(0); // harsh exit, might want something gentler
}
}
void thrd2()
{
uint64_t th2Count = 0;
m_rdy |= 0x02; // sync msg to main
do {
th2Sem.lock(); // wait for thrd1 to give permission
char t = kar;
th1Sem.unlock(); // give permission-to-proceed to thrd1
// simulate application - no duplicate spaces from input
th2Log += t;
th2Count += 1;
// end of sim
}while(!done);
ss2DR
<< "\n th2Count " << sops.digiComma(th2Count)
<< "\n th2Log " << th2Log
<< "\n thrd2 exit " << endl;
}
}; // class T946_t
} // namespace DTB
int main(int argc, char* argv[]) { return DTB::T946_t()(argc, argv); }
The output looks like:
ssIn: 'abcdefghij ...spaces... klmnopqrstuvwxyz'
ssIn.str().size(): 1,000,027
join()'s complete
T901_t::exec() duration 120,421,582 ns
th1Count 28
th1Skips 1,000,000
th1Log abcdefghij klmnopqrstuvwxyz
thrd1 exit
th2Count 28
th2Log abcdefghij klmnopqrstuvwxyz
thrd2 exit
The duration is 120 ms for 1 Million chars input.
As #Remy Lebeau pointed out you can get the repeat count by install WH_KEYBOARD hook and filter the key held pressed in KeyboardProc.
Of course, for simple, no need install a hook you can filter repeat WM_KEYDOWN messages in window procedure when you press the space key and hold. The following is an example you can refer to:
case WM_KEYDOWN:
if (wParam == VK_SPACE)
{
if (!((HIWORD(lParam) & 0x4000) || (HIWORD(lParam) & 0x8000)))
{
isKeyHold = TRUE; // First time pressed
OutputDebugString(TEXT("pressed !\n"));
}
else if (isKeyHold && (HIWORD(lParam) & 0x4000))
{
OutputDebugString(TEXT("hold !\n"));
return 1; // Don't handle the message when the key is pressed and held.
}
}
break;
case WM_KEYUP:
if (wParam == VK_SPACE && isKeyHold)
{
isKeyHold = FALSE; // Clear the isKeyHold flag when release the key.
OutputDebugString(TEXT("release !\n"));
}
break;

Creating 3 children processes and exiting them after a specified number of seconds

image for what output is supposed to look like:My problem is that I need to write a program that will accept the names of 3 processes as command-line arguments. Each of these processes will run for as many seconds as:(PID%10)*3+5 and terminate. After those 3 children terminated, the parent process
will reschedule each child. When all children have been rescheduled 3 times, the parent will terminate. I have used fork to create the three children but am struggling with getting them to exit with that specific criteria?
using namespace std;
int main(){
int i;
int pid;
for(i=0;i<3;i++) // loop will run n times (n=3)
{
if(fork() == 0)
{
pid = getpid();
cout << "Process p" << i+1 << " pid:" << pid << " Started..." << endl;
exit(0);
}
}
for(int i=0;i<5;i++) // loop will run n times (n=3)
wait(NULL);
}
You can use sigtimedwait to wait for SIGCHLD or timeout.
Working example:
#include <cstdio>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
template<class... Args>
void start_child(unsigned max_runtime_sec, Args... args) {
// Block SIGCHLD.
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, nullptr);
// Enable SIGCHLD.
signal(SIGCHLD, [](int){});
pid_t child_pid = fork();
switch(child_pid) {
case -1:
std::abort();
case 0: {
// Child process.
execl(args..., nullptr);
abort(); // never get here.
}
default: {
// paren process.
timespec timeout = {};
timeout.tv_sec = max_runtime_sec;
siginfo_t info = {};
int rc = sigtimedwait(&set, nullptr, &timeout);
if(SIGCHLD == rc) {
std::printf("child %u terminated in time with return code %d.\n", static_cast<unsigned>(child_pid), info.si_status);
}
else {
kill(child_pid, SIGTERM);
sigwaitinfo(&set, &info);
std::printf("child %u terminated on timeout with return code %d.\n", static_cast<unsigned>(child_pid), info.si_status);
}
}
}
}
int main() {
start_child(2, "/bin/sleep", "/bin/sleep", "10");
start_child(2, "/bin/sleep", "/bin/sleep", "1");
}
Output:
child 31548 terminated on timeout with return code 15.
child 31549 terminated in time with return code 0.
With these changes your program produces the desired output:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <iostream>
using namespace std;
int main()
{
for (int round = 0; ++round <= 4; )
{
int i;
cout << "*** ROUND: " << round << " ***\n";
for (i=0; i<3; i++) // loop will run n times (n=3)
{
if (fork() == 0)
{
int pid = getpid();
cout << "Process p" << i+1 << " pid:" << pid << " started...\n";
unsigned int seconds = pid%10*3+5;
cout << "Process " << pid << " exiting after "
<< seconds-sleep(seconds) << " seconds\n";
exit(0);
}
}
while (i--) // loop will run n times (n=3)
{
int status;
cout << "Process " << wait(&status);
cout << " exited with status: " << status << endl;
}
}
}
As Serge suggested, we're using sleep() for every child before exiting it. it will pause the process for a number of seconds.
To get the actual status information, we call wait(&status) instead of wait(NULL).
We're doing this all for the first scheduling round plus the desired 3 times of rescheduling.

How to access info about a thread throughout a program

Question 1: I am trying to name each thread so it can be used throughout the program but am receiving errors like "request for member 'fid' in 'planes[t]' which is of non-class type 'pthread_t'. It is referring to use of planes[t].tid or use of planes[t].startState. I'm not sure how else to get/save these values for each individual thread.
Question 2: once I have a thread's startState, how can I send the thread to a takeoff() function (series of switch states and printfs).
Question 3: What should be passed into the StartState function? I'm trying to have each thread remember its start state so that later in the code I can have a flight be "landing" or "taking off."
Here is the relevant code: Updated 10/06 at 22:37
#include <pthread.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include <queue>
#include <unistd.h>
#include <algorithm>
#include <time.h>
#include <ctime>
#define NUM_THREADS 3 //3 flights
using std::queue;
using std::vector;
pthread_mutex_t runway1lock;
pthread_mutex_t runway2lock;
bool run1occupied;
bool run2occupied;
struct flight_data{ //each plane has these characteristics
//void *FlightID;
long fid;
int startState; // if start=1 ==> taking off ::: if start=2 ==> landing
int flyTime; //fly == randomly generated time (order) of takeoff/land
};
struct flight_data flightinfo[NUM_THREADS];
void *FlightID(void *flightid){
struct flight_data *my_flights;
my_flights = (struct flight_data*)flightid;
int taskid;
taskid = my_flights->fid;
// long fid;
// fid = (long)flightid;
// printf("Flight #%1d\n", tid);
pthread_exit(NULL);
}
void Start(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
int startState;
srand(time(0));
my_flights.startState = rand() % 2+1;
std::string startstring;
if(my_flights.startState == 1){
startstring = "Taking off";
}
if(my_flights.startState == 2){
startstring = "Landing";
}
for(int i = 1; i<NUM_THREADS+1; i++){
std::cout << "Start state for Flight # " << i << " is " << startstring << std::endl;
}
}
void takeoff(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
for(int i = 1; i<NUM_THREADS+1; i++){
int state = my_flights.startState;
switch(state){
case 1:{ //G (GATE)
std::cout << "Flight # " << flightinfo[i].fid << " is listed as waiting at the gate." << std::endl;
std::cout << "Flight # " << flightinfo[i].fid << "'s position in queue for runway: " << flightinfo[i].flyTime << std::endl;
sleep(3);
state = 2;
break;
}
case 2: { //Q (queue) -- sets order for use of runway
queue<pthread_t> queue;
vector<int> flightTimes;
int soonestFlightTime = 10;
flightTimes.push_back(flightinfo[i].flyTime); //put all flight times into a vector called flightTimes
std::sort(flightTimes.begin(), flightTimes.end()); //sort the vector of flightTimes low to high
std::reverse(flightTimes.begin(), flightTimes.end()); //flips vector -- high(front) to low(back)
while(!flightTimes.empty()){
if (flightinfo[i].flyTime == flightTimes.back()){ //if a thread has the soonest flight time
queue.push(i); //then put the flight in the runway queue
flightTimes.pop_back(); //pop off the soonest flight time
}
}
while(!queue.empty()){
if(flightinfo[i].fid == queue.front()){
state = 3;
queue.pop();
sleep(3);
}
}
break;
}
case 3: { //CLR (clearance for runway)
std::cout << "Flight # " << flightinfo[i].fid << " has clearance to move to the runway." << std::endl; //will go in order of queue
if(run1occupied){
sleep(3);
}
// else if(collide){
// state = 7;
// }
else{
state = 4;
}
break;
}
case 4: { //RTO (runway takeoff)
pthread_mutex_lock(&runway1lock);
run1occupied = true;
std::cout << "Flight # " << flightinfo[i].fid << " is taking off. Runway occupied. Stand by." << std::endl;
sleep(3);
pthread_mutex_unlock(&runway1lock);
run1occupied = false;
state = 5;
break;
}
case 5: { //CZ (cruise)
std::cout << "Flight # " << flightinfo[i].fid << " is reaching proper altitude and cruising toward destination." << std::endl;
sleep(3);
// if(!collide){
state = 6;
// }
// else{
// state = 7; //collision!!!
// }
break;
}
case 6: { //RMV (remove from monitoring list)
std::cout << "Flight # " << flightinfo[i].fid << " has been removed from the monitoring list." << std::endl;
break;
}
case 7:{ //COLL (collision)
std::cout << "Collision in the air. There were many casualties." << std::endl;
break;
}
}
}
}
void landing(struct flight_data my_flights){
my_flights = (struct flight_data)my_flights;
for (int i = 0; i<NUM_THREADS; i++){
int state = my_flights.startState;
switch(state){
case 1:{ //ENTR (enter monitoring list)
state = 2;
break;
}
case 2:{ //Q (queue)
//if not the first thing in the queue then state = 4;
//otherwise state = 3;
}
case 3:{ //RWL (runway land)
state = 5;
break;
}
case 4:{ //HVR (hover)
//if first in queue then state = 3;
//otherwise stay here
//if collision state = 7;
}
case 5:{ //CLR (clearance to move to gate)
//if collision state = 7
//otherwise state = 6;
}
case 6:{ //G (gate)
}
case 7:{ //COLL (collision)
}
}
}
}
/*
bool collision(){
bool collide;
//random
if(){
collide = true;
}
else{
collide = false;
}
return collide;
}*/
int main(int argc, char *argv[]){
pthread_t flights[NUM_THREADS]; //pthread_t keeps a thread ID after the thread is created with pthread_create()
//it's like an index on a vector of threads
int *taskids[NUM_THREADS];
int rc;
long t;
for (t=1; t<=NUM_THREADS; t++){ //loop creates threads(flights)
printf("In main: Creating flight %1d\n", t);
flightinfo[t].fid= t;
rc = pthread_create(&flights[t], NULL, FlightID, (void *)&flights[t]);
if (rc){
printf("ERROR: return code from pthread_create() is %d\n", rc);
return (-1);
}
printf("Created flight %1d\n", t);
// Start(flightinfo[t]);
flightinfo[t].startState = rand() % 2+1;
std::cout << flightinfo[t].startState << std::endl;
if((flightinfo[t].startState)==1){
std::cout << "Flight # " << flightinfo[t].fid << " is listed with start state as " << flightinfo[t].startState << std::endl;
takeoff(flightinfo[t]);
//go to takeoff function and go through switch case
}
if((flightinfo[t].startState)==2){
std::cout << "Flight # " << flightinfo[t].fid << " is listed with start state as " << flightinfo[t].startState << std::endl;
landing(flightinfo[t]);
//go to landing function and go through switch case
}
}
pthread_exit(NULL);
}
It appears that you are confusing the pthread_t management variable, planes, with the variable containing the flight data, flights.
The pthread_t management variable, planes, is used by the pthread library and you should really only be using it as an argument to pthread library calls, otherwise just leave it alone and do not worry about it. Think of the variable planes as a storage area that you create and then give to the pthread library to use and by doing so you give ownership of that variable to the pthread library.
So the first order of business is to separate out and make distinct the difference between the pthread management and the actual data that is being manipulated by the threads.
You have several places where you are using the pthread management variable, planes, as if it is a flight data variable. It is not. Replace planes with flights
if((flights[t].startState)==1){
std::cout << "Flight # " << flights[t].fid << " is listed as waiting at the gate." << std::endl;
void takeoff();
//go to takeoff function and go through switch case
}
if((flights[t].startState)==2){
std::cout << "Flight # " << flights[t].fid << " is listed as waiting to land." << std::endl;
//go to landing function and go through switch case
}
This bit of source in your function StartState() does not make sense.
for(int i = 0; i<NUM_THREADS; i++){
startState = rand() % 1+2;
}
startState = my_flights->startState;
I suppose you are wanting to set a start state of a particular flight with some random start state. So I would expect the source to look like the following as I assume you are interested in setting the start state for a specific flight and the loop does not really do anything except exercise the random number generator NUM_THREADS times so the loop should just be replaced by something like the following. However I have not checked your logic on this and whether the range is correct or anything.
my_flights->startState = rand() % 1+2;
A Suggested Course of Action
You should think of a thread as being a little program or application. I suggest that for this simple example that you first of all write your flight logic without worrying about threads. So if you start with a function, say FlyPlaneFlight () to which you pass a flight variable and this function then calls other functions to do various things and when the flight ends, it returns to the caller, you will probably be in a good place for the threads. After having the logic in place for a single flight, you then use the pthread library to create multiple flights by initializing the flight data, and then creating a thread, that uses FlyPlaneFlight().
You also need to consider time and interaction. For this kind of a simulation, I suspect that you will want to have the FlyPlaneFlight() function to have a loop in which changes are made to the flight data and then the thread will sleep for a second or two. As a beginning test, use a for loop with a definite number of iterations and will then exit such as the following:
for (int i = 0; i < 100; i++) {
// modify the flight data
sleep(1000); // sleep for a second (1000 milliseconds) then repeat
}
If this becomes more complicated so that the flights are not independent but must be synchronized in some way, you will need to look into the thread synchronization functions of the pthread library.
So when you wrap your FlyPlaneFlight() function into a pthread_create() function, it might look something like the following source snip:
void *FlightID(void *flightdata){
struct flight_data *my_flights = (struct flight_data*)flightdata;
// initialize the flight data as needed
FlyPlaneFlight (myFlight);
// print out the myFlight data so that you can see what happened
pthread_exit(NULL);
}
The idea is to treat the plane flight as an object and all of the needed data for the flight is in the struct flight_data struct and that for the most part you can ignore the pthread library which is not involved in the actual flying simulation but rather is used to allow for the simulation of multiple flying objects. So you create multiple threads, each of which has its own flight data and then uses the same code to process the flight data. You do a bit of randomization so that all of the various flights will have different histories, they will do different things.
Edit
Your main would then have a loop something like the following
for (t=0; t<NUM_THREADS; t++){ //loop creates threads(flights)
std::cout << "In main: Creating flight " << t+1 << std::endl;
flights[t].fid= t+1;
rc = pthread_create(&planes[t], NULL, FlightID, (void *)&flights[t]);
if (rc){
std::cout << "ERROR: return code from pthread_create() is " << rc << std::endl;
return (-1);
}
std::cout << "Created flight " << t << std::endl;
}
pthread_exit(NULL); // exit the main thread and allow remaining threads to complete
This will create your various threads and let them run. In the loop in the FlyPlaneFlight() function you would have the status print outs something like the following each time through the loop so your FlyPlaneFlight() function would look something like and you would use a kind of finite state machine to move from state to state possibly using a random number generator to roll a virtual dice using the rand() function as in these examples to determine the next state or to remain in the current state:
void FlyPlaneFlight (struct flight_data *my_flights)
{
for (int i = 0; i < 100; i++) {
switch (my_flights->startState) {
case 1:
std::cout << "Flight # " << my_flights->fid << " is listed as waiting at the gate." << std::endl;
// now move the flight state to the next state.
break;
case 2:
std::cout << "Flight # " << my_flights->fid << " is listed as waiting to land." << std::endl;
// now move the flight state to the next state.
break;
// other case statements for other flight states and moving between the
// various flight states.
}
sleep (1000); // sleep this thread for one second (1000 milliseconds) then repeat
}
}
EDIT #2 based on source update 10/06 at 22:37
In your source you have a global array variable, flights, that you are trying to access directly through out your source. This is a mistake that is leading you into problems. What you need to do is to have your thread create call to allocate a particular array element of flights to the particular thread. Then at that point you do not worry about the flights array but instead work with only the particular element assigned to that thread.
For instance use the thread create as follows which creates a thread and assigns a unique array element to the thread being created.
rc = pthread_create(&planes[t], NULL, FlightID, (void *)&flights[t]);
The thread entry function, FlightID() accepts as an argument a pointer to that array element so at that point any of your functions that operate on the flight data in flights[t] can just use that pointer to that array element. The functions should only be worried about their particular flight and not everyone else's flight as well.
Also after the thread is started, the function FlightID() and any function it calls should no longer be concerned about other threads so all these loops with NUM_THREADS in these functions should not be there.
The idea is to have a small program that is started by calling FlightID() which operates on the particular flight. Then with multiple threads each thread starts at FlightID(). So this is similar to the idea of main() being the entry point for a C/C++ program where main() has some arguments and your program starts at main(). In the case of threads, the thread starts at the thread entry function which in your case is FlightID().
The reason I have a loop in FlyPlaneFlight() is to provide a series of state changes for a finite state machine for a particular flight. In other words what is inside the loop is a plane flight.
Look at the difference between my suggested thread creation loop and your's. Mine does nothing more than create threads. Your's creates threads and then tries to do things with the flights array element which really should now belong to the thread created and not the main.
All those variables appear to be stored in the flights array, not the planes array.

Barrier Synchronization between 2 process using mutex

I need to implement barrier synchronization between 2 threads using mutex (only). Barrier synchronization is that 2 threads will wait for each other to meet at predefined step before proceeding.
I am able to do it using seamaphore but how can I achieve this only using mutex. I was given a hint that I need 2 mutex not 1 to do this.
Using Seamaphore:
#include <pthread.h>
#include <semaphore.h>
using namespace std;
sem_t s1;
sem_t s2;
void* fun1(void* i)
{
cout << "fun1 stage 1" << endl;
cout << "fun1 stage 2" << endl;
cout << "fun1 stage 3" << endl;
sem_post (&s1);
sem_wait (&s2);
cout << "fun1 stage 4" << endl;
}
void* fun2(void* i)
{
cout << "fun2 stage 1" << endl;
cout << "fun2 stage 2" << endl;
// sleep(5);
sem_post (&s2);
sem_wait (&s1);
cout << "fun2 stage 3" << endl;
}
main()
{
sem_init(&s1, 0, 0);
sem_init(&s2, 0, 0);
int value;
sem_getvalue(&s2, &value);
cout << "s2 = " << value << endl;
pthread_t iThreadId;
cout << pthread_create(&iThreadId, NULL, &fun2, NULL) << endl;
// cout << pthread_create(&iThreadId, NULL, &fun2, NULL) << endl;
pthread_create(&iThreadId, NULL, &fun1, NULL);
sleep(10);
}
Compile the above code as "g++ barrier.cc -lpthread"
How about NO MUTEXES and no locks? Using ATOMIC OPERATIONS only:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
static sigset_t _fSigSet;
static volatile int _cMax=20, _cWait = 0;
static pthread_t _aThread[1000];
void * thread(void *idIn)
{
int nSig, iThread, cWait, id = (int)idIn;
printf("Start %d\n", id, cWait, _cMax);
// do some fake weork
nanosleep(&(struct timespec){0, 500000000}, NULL);
// barrier
cWait = __sync_add_and_fetch(&_cWait, 1);
printf("Middle %d, %d/%d Waiting\n", id, cWait, _cMax);
if (cWait < _cMax)
{
// if we are not the last thread, sleep on signal
sigwait(&_fSigSet, &nSig); // sleepytime
}
else
{
// if we are the last thread, don't sleep and wake everyone else up
for (iThread = 0; iThread < _cMax; ++iThread)
if (iThread != id)
pthread_kill(_aThread[iThread], SIGUSR1);
}
// watch em wake up
cWait = __sync_add_and_fetch(&_cWait, -1);
printf("End %d, %d/%d Active\n", id, cWait, _cMax);
return 0;
}
int main(int argc, char** argv)
{
pthread_attr_t attr;
int i, err;
sigemptyset(&_fSigSet);
sigaddset(&_fSigSet, SIGUSR1);
sigaddset(&_fSigSet, SIGSEGV);
printf("Start\n");
pthread_attr_init(&attr);
if ((err = pthread_attr_setstacksize(&attr, 16384)) != 0)
{
printf("pthread_attr_setstacksize failed: err: %d %s\n", err, strerror(err));
exit(0);
}
for (i = 0; i < _cMax; i++)
{
if ((err = pthread_create(&_aThread[i], &attr, thread, (void*)i)) != 0)
{
printf("pthread_create failed on thread %d, error code: %d %s\n", i, err, strerror(err));
exit(0);
}
}
for (i = 0; i < _cMax; ++i)
pthread_join(_aThread[i], NULL);
printf("\nDone.\n");
return 0;
}
I am not sure that you need two mutexes, with one mutex and a condition variable and an extra flag might be enough. The idea is that you enter the critical section by acquiring the mutex, then you check whether you are the first thread to come, if so, you wait on the condition. If you are the second thread coming then you wake up the waiting thread and both leave.