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

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;

Related

I/O in concurrent program

I'm working on a concurrent program; it has two threads, one of which listens messages from a server and the other one sends messages to it.
I need to obtain commands from the user (using cin?) and show messages coming from the server both at the same time.
How can I handle that situation? The problem is that if I'm reading a command from the user when a message comes, the user's input is messed up with other stuff.
Thanks in advance
Some alternatives
have your command dump all the messages that have occurred since the last invocation of the command. That way the output is finite.
have your cli command monitor all traffic continuously until ctrl-c (or some other key combination) is pressed then it reverts back to your application's cli prompt.
have your cli command send data to a file and monitor that with a tail type tool
I took my old sample code and tried to turn it into an MCVE. ("Minimal" does not necessarily mean "short", does it?)
This is a very simple concept of a "shell" which supports one thread for input while multiple threads may do output.
The keyboard input is done non-echoing. This is non-portable. Therefore I provide two implementations of function getChar() – one for MS Windows and another for non-MS Windows (which considers actually only *ix OSes). The latter is "strongly inspired" by SO: How to implement getch() function of C in Linux?.
The input characters are stored in a std::string.
The output erases the prompt and the current input text (repeating the output of "\b \b" resp.), prints the output text (incl. newline), and prints the prompt and current input buffer again.
The output is mutex guarded to grant thread-safety.
This is the sample code miniShell.cc:
// system header:
#ifdef _WIN32
#include <conio.h>
#else // (not) _WIN32
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#endif // _WIN32
/// reads a character from console without echo.
#ifdef _WIN32
inline int getChar() { return _getch(); }
#else // (not) _WIN32
int getChar()
{
struct termios oldattr;
tcgetattr(STDIN_FILENO, &oldattr);
struct termios newattr = oldattr;
newattr.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
const int ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
return ch;
}
#endif // _WIN32
// standard C/C++ header:
#include <cstring>
#include <mutex>
#include <string>
/* provides a class for a simple thread-safe mini-shell.
*
* It is assumed that one thread may await user input (read()) while
* another thread may (or may not) output text from time to time.
* The mini-shell grants that the input line is always the last line.
*/
class Console {
// variable:
private:
// mutex for console I/O
std::mutex _mtx;
// current input
std::string _input;
// prompt output
std::string _prompt;
// methods:
public:
/// constructor.
Console() { }
// disabled:
Console(const Console&) = delete;
Console& operator = (const Console&) = delete;
// reads a line from console and returns input string
std::string read();
/* writes text to console.
*
* text the text
* size size of text
*/
void write(const char *text, size_t size);
void write(const char *text) { write(text, strlen(text)); }
void write(const std::string &text) { write(text.c_str(), text.size()); }
};
// standard C/C++ header:
#include <atomic>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <thread>
std::string Console::read()
{
{ // activate prompt
std::lock_guard<std::mutex> lock(_mtx);
_prompt = "> "; _input.clear();
std::cout << _prompt << std::flush;
}
#ifdef _WIN32
enum { Enter = '\r', BackSpc = '\b' };
#else // (not) _WIN32
enum { Enter = '\n', BackSpc = 127 };
#endif // _WIN32
// input loop
for (;;) {
switch (int c = getChar()) {
case Enter: {
std::lock_guard<std::mutex> lock(_mtx);
std::string input = _input;
_prompt.clear(); _input.clear();
std::cout << std::endl;
return input;
} // unreachable: break;
case BackSpc: {
std::lock_guard<std::mutex> lock(_mtx);
if (_input.empty()) break; // nothing to do
_input.pop_back();
std::cout << "\b \b" << std::flush;
} break;
default: {
if (c < ' ' || c >= '\x7f') break;
std::lock_guard<std::mutex> lock(_mtx);
_input += c;
std::cout << (char)c << std::flush;
} break;
}
}
}
void Console::write(const char *text, size_t len)
{
if (!len) return; // nothing to do
bool eol = text[len - 1] == '\n';
std::lock_guard<std::mutex> lock(_mtx);
// remove current input echo
if (size_t size = _prompt.size() + _input.size()) {
std::cout
<< std::setfill('\b') << std::setw(size) << ""
<< std::setfill(' ') << std::setw(size) << ""
<< std::setfill('\b') << std::setw(size) << "";
}
// print text
std::cout << text;
if (!eol) std::cout << std::endl;
// print current input echo
std::cout << _prompt << _input << std::flush;
}
// a sample application
// shared data for main thread and data processing thread
struct Shared {
// flag: true ... exit communication thread and main loop
std::atomic<bool> exit;
// flag: true ... start data processing
std::atomic<bool> start;
// the mini console
Console console;
// constructor.
Shared(): exit(false), start(true) { }
};
void dataProc(Shared &shared)
{
while (!shared.exit) {
// "busy" wait for start (condition would be more elegant)
while (!shared.start) {
if (shared.exit) return;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// do data processing
shared.console.write("Starting data processing.");
for (int i = 0, n = 20; i < n; ++i) {
// "busy" wait for start (condition would be more elegant)
if (!shared.start) {
shared.console.write("Data processing stopped.");
while (!shared.start) {
if (shared.exit) return;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
shared.console.write("Data processing restarted.");
}
// consume some time (to simulate heavy computation)
std::this_thread::sleep_for(std::chrono::milliseconds(250));
// do some console output about progress
{ std::ostringstream fmt;
fmt << "Step " << i + 1 << '/' << n;
shared.console.write(fmt.str());
}
}
shared.console.write("Data processing done.");
shared.start = false;
}
}
void processInput(const std::string &input, Shared &shared)
{
if (input == "start") shared.start = true;
else if (input == "stop") shared.start = false;
else if (input == "exit") shared.exit = true;
else if (input.size()) shared.console.write("Wrong command!");
}
int main()
{
Shared shared;
// start a thread for some kind of data processing
std::thread threadDataProc(&dataProc, std::ref(shared));
// main loop
while (!shared.exit) {
shared.console.write("Commands: start stop exit");
std::string input = shared.console.read();
processInput(input, shared);
}
// join data processing thread
threadDataProc.join();
// done
return 0;
}
I compiled and tested in VS2013 vs. bash/Xterm of cygwin on Windows 10.
(cygwin was the closest to Linux I have at hand.)
Please, keep in mind that I wrote this code whereby simplicity was more important than perfection or comfort.

How do I send data back along the second pipe in the correct format?

I have been struggling for two days to attempt to fix this final bug in my code, but can't seem to find the error. The code is supposes to(in order):
Receive a string from the user (in this case me)
Create a child process
Send the string to the child process
Rework the string so that every word starts with a capital letter
Send the string back to the parent with the changes
Display the string
The code runs fine until the parent read. An example output is:
Input: "helLO tHerE"
Parent writes "helLO tHerE"
Child reads "helLO tHerE"
Child writes "Hello There"
Parent reads ##$%^$#%^&* - or some other such non-standard characters, then displays error -
double free or corruption (out): 0x00007ffeeebb2690 ***
Below is my code:
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <algorithm>
using namespace std;
int main(){
int fd[2];
int pfc[2];
int status = 0;
string val = "";
if(pipe(fd) == -1 || pipe(pfc) == -1) fprintf(stderr,"Pipe failed");
pid_t pid = fork();
// fork() returns 0 for child process, child-pid for parent process.
if (pid == 0){ // child: reading only, so close the write-descriptor
string writeval = "";
close(fd[1]);
// now read the data (will block)
read(fd[0], &val, sizeof(val));
cout << "Child reads " << val.c_str() << endl;
string temp = " " + val;
transform(temp.begin(), temp.end(), temp.begin(), ::tolower);
for(size_t i = 1; i < temp.length(); i++){
if(!isspace(temp[i]) && isspace(temp[i-1])){
temp[i] = toupper(temp[i]);
}
}
writeval = temp.substr(1, temp.length() - 1);
// close the read-descriptor
close(fd[0]);
close(pfc[0]);
cout << "Child writes " << writeval.c_str() << endl;
write(pfc[1], &writeval, sizeof(writeval));
close(pfc[1]);
exit(0);
}
else{
string readval = "";
string temp ="";
// parent: writing only, so close read-descriptor.
close(fd[0]);
// send the value on the write-descriptor.
while(getline(cin, temp)){
val += temp;
}
write(fd[1], &val, sizeof(val));
cout << "Parent writes " << val << endl;
// close the write descriptor
close(fd[1]);
//wait(&status);
close(pfc[1]);
read(pfc[0], &readval, sizeof(readval));
cout << "Parent reads " << readval << endl;
close(pfc[0]);
}
return 0;
}
So the answer is simple. In the child process I was passing the memory location of writeval in the write back to the parent method, but in the parent process I was trying to read from the memory location of readval. This is fixed by changing them to be the same variable, outside of the if/else calls, like was done with the variable val.
See here for more details on why this is a problem.

Why is my C++ array printing the same values?

I am working on a code where it will do Linux command piping. Basically in my code, it will parse the user input command, then run it using the execvp function.
However, to do this, I would need to know the command, as well as its parameters. I have been trying to get the parsing to work correctly, however, it seems that when I do a test case, the output from both of the arrays that store their respective programs is the same. The commands/parameters are stored in a char array called prgname1 and prgname2.
For instance, if I were to run my program with the parameter "ps aux | grep [username]", then the output of prgname1[0] and prgname2[0] are both [username]. They are supposed to be ps and grep, respectively.
Can anyone take a look at my code and see where I might be having an error which is causing this?
Thanks!
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
#define MAX_PARA_NUM 5
#define MAX_COMMAND_LEN 1024
using namespace std;
int main(int argc, char *argv[]) {
char *prgname1[MAX_PARA_NUM], *prgname2[MAX_PARA_NUM];
char command[MAX_COMMAND_LEN];
int pfd[2];
pipe(pfd);
pid_t cid1, cid2;
char *full = argv[1];
char str[MAX_COMMAND_LEN];
int i = 0;
int j = 0;
int k = 0;
int ind = 0;
while (ind < strlen(full)) {
if (full[ind] == ' ') {
strncpy(command, str, i);
cout << command << endl;
prgname1[j] = command;
j++;
i = 0;
ind++;
}
else {
str[i] = full[ind];
i++;
ind++;
}
if(full[ind] == '|') {
i = 0;
j = 0;
ind+=2;
while (ind < strlen(full)) {
if (full[ind] == ' ') {
strncpy(command, str, i);
cout << command << endl;
prgname2[j] = command;
j++;
i = 0;
ind++;
}
else {
str[i] = full[ind];
i++;
ind++;
}
if (ind == strlen(full)) {
strncpy(command, str, i);
cout << command << endl;
prgname2[j] = command;
break;
}
}
}
}
// test output here not working correctly
cout << prgname1[0] << endl;
cout << prgname2[0] << endl;
// exits if no parameters passed
if (argc != 2) {
cout << "Usage:" << argv[0] << endl;
exit(EXIT_FAILURE);
}
// exits if there is a pipe error
if (pipe(pfd) == -1) {
cerr << "pipe" << endl;
exit(EXIT_FAILURE);
}
cid1 = fork(); // creates child process 1
// exits if there is a fork error
if (cid1 == -1 || cid2 == -1) {
cerr << "fork";
exit(EXIT_FAILURE);
}
// 1st child process executes and writes to the pipe
if (cid1 == 0) {
char **p = prgname1;
close(1); // closes stdout
dup(pfd[1]); // connects pipe output to stdout
close(pfd[0]); // closes pipe input as it is not needed
close(pfd[1]); // closes pipe output as pipe is connected
execvp(prgname1[0], p);
cerr << "execlp 1 failed" << endl;
cid2 = fork();
}
// 2nd child process reads from the pipe and executes
else if (cid2 == 0) {
char **p = prgname2;
close(0); // closes stdin
dup(pfd[0]); // connects pipe input to stdin
close(pfd[0]); // closes pipe input as pipe is connected
close(pfd[1]); // closes pipe output as it is not needed
execvp(prgname2[0], p);
cerr << "execlp 2 failed" << endl;
}
else {
sleep(1);
waitpid(cid1, NULL, 0);
waitpid(cid2, NULL, 0);
cout << "Program successfully completed" << endl;
exit(EXIT_SUCCESS);
}
return 0;
}
argv[1] gives you the first argument on the command line - not the entire command line. If you want the full list of command line arguments passed into the process, you will need to append argv[1], argv[2], ..., argv[argc - 1] together with a space between each.
Additionally, when you process it, you are setting the pointer for your prgname1[index] to command, so every time you set a given character pointer, they are all pointing to the same location (hence, they are all the same value). You need to allocate space for each element in prgname1 and copy command into it (using strncpy). Alternatively, using std::string and std::vector eliminates much of your current code.

naming threads, using typedef/struct

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]){

How to skip cin on purpose in C++?

I need to have a while-loop running and accept input to it whenever there is an input. I'm not new to C++, but this hurdle is quite difficult. Due to an NDA (this school project is apparently some secret stuff) I can only show you the test case.
I've been grasping for straws trying to solve the problem; try catch, cin.get, cin.peek, if(cin.peek){}. If anybody can point me in the right direction I would be very grateful!
The program is not time-critical, but a function needs to be called with a fixed interval. It is not essential that the code is portable, that it is a while-cin-combination or anything like that; the code will only ever run on a Windows 7 or Windows 8 PC with at least dual core processor.
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
int input = 0;
int pastTime, nowTime;
pastTime = nowTime = time(0);
cin >> input;
while(input != -1)
{
if(input == 1)
{
cout << "Entered 1" << endl;
//To be done instead of the two 'elses',
//bypassing interval-dependant code
}
else if(input == 2)
{
cout << "Entered 2" << endl;
//To be done instead of the interval-dependant code
}
else if(pastTime == (nowTime - 5))
{
cout << "Nothing entered." << endl;
//Needs to be done with a fixed interval.
}
nowTime = time(0);
cin >> input;
}
return 0;
}
The solution was, based om James Beilby's link:
// This program is based on counter.cpp from Boost\lib\thread\tutorial
#include <boost/thread/thread.hpp>
#include <iostream>
#include <ctime>
int timeNow = time(0);
int timePast = time(0);
void fct_one()
{
while(1) //keeps running all the time
{
if(timePast == (timeNow - 3)) // only executed once every three seconds
{
//do some stuff
timePast = time(0);
}
timeNow = time(0); // time is continuously updated
}
}
void fct_two()
{
int input = 0;
int timeTemp = time(0);
while(1) //keeps running all the time
{
std::cin >> input; // cin blocking for input
if(input == 1)
{
//do some stuff
}
if(input == 2)
{
//do some stuff
}
if(input == -1)
{
std::cout << "Program is done. ";
system("pause");
exit(1);
}
}
}
int main()
{
boost::thread_group threads;
threads.create_thread(&fct_one)
threads.create_thread(&fct_two);
threads.join_all();
return 0;
}
I would completely separate reading input from cin and performing the default timeout function. You'll need something like a background thread that performs the default function based on the time interval. To handle the 1st two cases you'll need to signal the thread skipping the next execution (if this is really necessary), and just call any function you want or do nothing.
The simple answer is to put the code that runs at some interval on another thread. Since you've noted this is Windows, you could use a Timer Queue:
Begin with routines to start and stop your time dependent work:
HANDLE Start(HANDLE hTimerQueue)
{
DWORD timerMS = 5000; /* every 5 seconds */
HANDLE hTimer;
if (!CreateTimerQueueTimer(&hTimer,
hTimerQueue,
(WAITORTIMERCALLBACK)timerWork,
/*lpParam*/NULL,
/*start in ___ ms:*/0,
/*run every __ ms:*/timerMS,
/*flags*/0))
{
return NULL;
}
return hTimer;
}
BOOLEAN Stop(HANDLE hTimerQueue, HANDLE hTimer)
{
if (!DeleteTimerQueueTimer(hTimerQueue,
hTimer,
/*wait for our timer to complete*/INVALID_HANDLE_VALUE))
{
return FALSE;
}
return TRUE;
}
Then put your time dependent work into its own callback:
VOID CALLBACK timerWork(PVOID lpParam, BOOLEAN TimerOrWaitFired /*ignored*/)
{
for (int ii = 0; ii < 10; ++ii) {
std::cout << "timer work: " << ii << std::endl;
Sleep(250);
}
}
Finally, integrate these into your workflow:
int main(int argc, char* argv[])
{
HANDLE hTimerQueue = CreateTimerQueue(hTimerQueue);
if (NULL == hTimerQueue) return -1;
HANDLE hTimer = Start(hTimerQueue);
if (NULL == hTimer) return -1;
/* our timed callback is now running in the background */
int input = 0;
std::cin >> input;
while(input != -1)
{
if(input == 1)
{
if (Stop(hTimerQueue, hTimer)) {
std::cout << "Entered 1" << std::endl;
if (NULL == (hTimer = Start(hTimerQueue))) return -2;
}
}
else if(input == 2)
{
if (Stop(hTimerQueue, hTimer)) {
std::cout << "Entered 2" << std::endl;
if (NULL == (hTimer = Start(hTimerQueue))) return -2;
}
}
std::cin >> input;
}
DeleteTimerQueue(hTimerQueue);
return 0;
}