libreadline SIGINT handler doesn't clear buffer - c++

Having the little program below I expect the following:
>> forget_me!^C
>> next
next
>>
But it really is:
>> forget_me!^C
>> next
forget_me!next
>>
Shouldn't the default SIGINT handler clear the buffer as described here http://sunsite.ualberta.ca/Documentation/Gnu/readline-4.1/html_node/readline_40.html#SEC40 (rl_free_line_state)?
How can I achieve the desired result?
#include <cstdlib>
#include <csignal>
#include <iostream>
#include <readline/readline.h>
#include <readline/history.h>
const std::string prompt{">> "};
void new_line_handler(int i) { std::cout << "\n" << prompt; }
int main() {
struct sigaction action = {};
action.sa_handler = new_line_handler;
sigaction(SIGINT, &action, nullptr);
char *input;
while (true) {
input = readline(prompt.c_str());
if (!input)
break;
add_history(input);
std::cout << input << "\n";
free(input);
}
return 0;
}

Related

Keep running a program without any intervention till its asked to quit

The below code expects the user to key in a character on every loop. If I want to keep running this loop without user having to enter any character on every loop till the number 0 is keyed in, how do i achieve it.
#include<iostream>
int main()
{
int i = 1;
int ch = 1;
while (ch != 0)
{
std::cin >> ch;
std::cout << "Hi" << i << std::endl;
++i;
}
return 1;
}
Threading is your only possibility. Also it always requires the ENTER when you are using std::cin. This could work:
#include <future>
#include <iostream>
#include <thread>
int main(int argc, char** argv) {
int i = 1;
std::atomic_int ch{1};
std::atomic_bool readKeyboard{true};
std::thread t([&ch, &readKeyboard]() {
while (readKeyboard) {
int input;
if (std::cin >> input) {
ch = input;
if (ch == '0') {
break;
}
}
}
});
while (ch != '0') {
std::cout << "Hi" << i << std::endl;
++i;
}
readKeyboard = false;
t.join();
return 1;
}
You can do this but you will have to use threads. Here is the minimal example how to achive this behaviour. Please note that you will need C++11 at least.
#include <iostream>
#include <thread>
#include <atomic>
int main()
{
std::atomic<bool> stopLoop;
std::thread t([&]()
{
while (!stopLoop)
{
std::cout << "Hi";
}
});
while (std::cin.get() != '0') //you will need to press enter after pressing '0'
{
; //empty loop, just wait until there is 0 on input
}
stopLoop = true; //this stops the other loop
}
Other options will be to dive into OS specific libraries. You must now that C++ doesn't have any kind of non-blocking I/O in standard library and for most time you will have to press <ENTER> to have any input in input stream (std::cin)

Using multithreading to get continuous beep sound

I'm trying to create a program in C++ where I play a beep sound, with a frequency and duration of the user's choice.
The program needs to continue running while playing the beep sound.
I figured out I should use multi-threading for this, but I don't have any experience with this.
For example, this is a simple program, but I get an error when I use _beginthread:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <process.h>
using namespace std;
int freq = 0;
int sec = 0;
int mil = 0;
void beepTone(int freqq, int mill)
{
Beep(freqq, mill);
_endthread();
}
int main()
{
cout << "Frequency?" << endl;
cin >> freq;
cout << "Duration?" << endl;
cin >> sec;
mil = 1000 * sec;
_beginthread(beepTone(freq, mil), 0, NULL);
cout << "Test Threading";
return 0;
}
Argument of type "void(*)(int freqq, int mill)" is incompatible with parameter of type "_beginthread_proc_type"
I think the point of this testing program is pretty clear.
I have code that runs, but in this code I can't choose my own frequency and duration:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <process.h>
using namespace std;
void beepTone(void *arg)
{
Beep(1000, 3000);
_endthread();
}
int main()
{
_beginthread(beepTone, 0, NULL);
cout << "Test Threading";
cin.get();
return 0;
}
This one plays 1000Hz for 3 sec while continuing the program.
Can anyone help me on how can I tell the thread which frequency and duration to play?
Your first example fails to compile because you are actually calling beepTone() and then trying to pass its void return value to the start_address parameter of _beginthread(), which will not work. You need to pass beepTone() itself to that parameter, not its return value.
Your second example is correctly passing beepTone() itself to _beginThread(), but is not passing any data to beepTone().
Now, to accomplish what you want, _beginthread() has an arglist parameter that you can use to pass user data to your thread function. That is what you need to use to send your beep values to the thread so it can then pass them to Beep().
Try something like this:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <iostream>
using namespace std;
struct beepParams
{
int freq;
int mil;
};
void __cdecl beepTone(void *arg)
{
beepParams *params = static_cast<beepParams*>(arg);
Beep(params->freq, params->mil);
delete params;
_endthread();
}
int main()
{
int freq = 0, sec = 0, mil = 0;
cout << "Frequency?" << endl;
cin >> freq;
cout << "Duration?" << endl;
cin >> sec;
mil = 1000 * sec;
beepParams *params = new beepParams;
params->freq = freq;
params->mil = mil;
if (_beginthread(&beepTone, 0, params) == -1)
delete params;
cout << "Test Threading";
//...
cin.get();
return 0;
}
That being said, if you are using C++11 or later, consider using std::thread instead:
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <thread>
using namespace std;
struct beepParams
{
int freq;
int mil;
};
void beepTone(beepParams params)
{
Beep(params.freq, params.mil);
}
int main()
{
int freq = 0, sec = 0, mil = 0;
cout << "Frequency?" << endl;
cin >> freq;
cout << "Duration?" << endl;
cin >> sec;
mil = 1000 * sec;
beepParams params;
params.freq = freq;
params.mil = mil;
thread t(beepTone, params);
t.detach();
cout << "Test Threading";
//...
cin.get();
return 0;
}

C++ Program Compiles in Windows and Linux. But Doesn't Work on Linux

I think it might be something related to the way my pointers are used/initialized in my struct, but I'm not completely sure. I use 'g++ -lpthread main.cpp' to compile. The program just hangs in Linux, while executing properly in windows. The program doesn't even spit out a cout I put in the beginning of the code for debugging purposes.
#include "pthread.h"
#include "semaphore.h"
#include "time_functions.h"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;
struct vars {
char buffer[10][1000];
int put;
int take;
sem_t openSlot;
sem_t slotInactive;
sem_t newData;
ifstream readFile;
ofstream writeFile;
};
void *write(void *in) //consumer, writes data to file and deletes data from buffer
{
vars* writeVars = (vars*)in;
while (true)
{
sem_wait(&(*writeVars).newData);
sem_wait(&(*writeVars).slotInactive);
if ((*writeVars).buffer[(*writeVars).take % 10][0] != '$')
{
(*writeVars).writeFile << (*writeVars).buffer[(*writeVars).take % 10];
if ((*writeVars).readFile.eof() != true)
{
(*writeVars).writeFile << endl;
}
else
{
break;
}
}
(*writeVars).take++;
sem_post(&(*writeVars).openSlot);
sem_post(&(*writeVars).slotInactive);
}
pthread_exit(0);
return 0;
}
void *read(void *in) //producer, reads data into buffer
{
vars* readVars = (vars*)in;
char read_line[1000];
while ((*readVars).readFile.getline(read_line, 1000))
{
sem_wait(&(*readVars).openSlot);
sem_wait(&(*readVars).slotInactive);
strcpy((*readVars).buffer[(*readVars).put % 10], read_line);
(*readVars).put++;
sem_post(&(*readVars).slotInactive);
sem_post(&(*readVars).newData);
}
sem_wait(&(*readVars).openSlot);
sem_wait(&(*readVars).slotInactive);
(*readVars).buffer[(*readVars).put % 10][0] = '$';
sem_post(&(*readVars).slotInactive);
sem_post(&(*readVars).newData);
pthread_exit(0);
return 0;
}
int main(int argc, char* argv[])
{
char pause[10];
vars *varsPointer, var;
varsPointer = &var;
var.take = 0;
var.put = 0;
var.writeFile.open(argv[2], ios::out);
var.readFile.open(argv[1], ios::in);
start_timing();
sem_init(&var.openSlot, 0, 10);
sem_init(&var.slotInactive, 0, 1);
sem_init(&var.newData, 0, 0);
pthread_t read_Thread, write_Thread;
pthread_create(&read_Thread, NULL, read, varsPointer);
pthread_create(&write_Thread, NULL, write, varsPointer);
pthread_join(read_Thread, NULL);
pthread_join(write_Thread, NULL);
sem_destroy(&var.openSlot);
sem_destroy(&var.slotInactive);
sem_destroy(&var.newData);
stop_timing();
var.readFile.close();
var.writeFile.close();
//Display timer
cout << "wall clock time (ms):" << get_wall_clock_diff() * 1000 << '\n';
cout << "cpu time (ms):" << get_CPU_time_diff() * 1000 << '\n';
cout << "Type Something and Press Enter To Continue";
cin >> pause; //Just used to keep cmd promt open in Windows after program execution
return 0;
}

How to tell my program to do something while waiting to get a command from the user?

I'm trying to make a timer which will count from the amount of time the user commands it, to zero.
Now I'm trying to add a pause faction to it, which will require to my programm to accept and read input while the timer ticks.
This is the code I have so far -
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <dos.h>
#include <windows.h>
using namespace std;
// sleep(5000);
int seconds;
int hoursLeft;
int minutesLeft;
int secondsCount=0;
void timeLeft ()
{
hoursLeft = seconds/3600;
minutesLeft = seconds/60 - hoursLeft*60;
}
void timer ()
{
if (secondsCount == 60)
{
timeLeft();
cout << "The Amount of time left is: " << hoursLeft << " hours and " << minutesLeft << " minutes left." << endl;
secondsCount=0;
}
secondsCount++;
seconds--;
Sleep(1000);
timer();
}
int main()
{
// introduction and time picking
cout << "Welcome to my Timer - Please set the amount of hours and than minutes you want the timer to run" << endl;
double requestedHours, requestedMinutes;
cin >> requestedHours;
cin >> requestedMinutes;
double requestedSeconds = requestedHours*3600 + requestedMinutes*60;
seconds = requestedSeconds;
cout << "Timer Started";
timer();
}
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
int main()
{
char buffer[16];
int flags;
int fd;
int r;
fd = 0; //stdin
flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
while (1)
{
memset(buffer, 0, sizeof(buffer));
r = read(0, buffer, sizeof(buffer)); //return the number of bytes it reads
if (r > 0) //something was read
{
printf("read: %d\n", buffer[0]);
fflush(stdin);
}
else //nothing has been read
{
puts("update timer here");
}
usleep(50000);
}
return (0);
}
using non blocking read on file descriptor can also be cool
sorry i only have this solution in C
PS: You're computer isnt suppose to work recursively infinitly, you should use a loop instead of an infinite recursion (timer() recalls itself), or your stack will overflow

Want to update a QtableWidget within a QThread

I'm starting a project called Nice System Monitor aiming to monitor processes on Linux, and I'm using C++ and Qt with QtCreator.
I've started making a QThread with a function called to fill a QTableWidget repeatedly but the table doesn't update properly even if I delete each row before fulling it up again.
I'm quite new to Qt and inspired myself of different sources on the Internet.
Here's the code of the QThread :
#include <unistd.h>
#include <ios>
#include <iostream>
#include <fstream>
#include <string>
#include <dirent.h>
#include <stdio.h>
#include <cctype>
#include <stdlib.h>
#include <vector>
#include <sstream>
#include "renderprocesstablethread.h"
#include <proc/readproc.h>
#include <proc/procps.h>
#include "mainwindow.h"
using namespace std;
RenderProcessTableThread::RenderProcessTableThread(QObject *parent)
: QThread(parent)
{
restart = false;
abort = false;
}
RenderProcessTableThread::~RenderProcessTableThread()
{
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
wait();
}
bool RenderProcessTableThread::isNum(char *s) {
int i = 0, flag;
while(s[i]){
//if there is a letter in a string then string is not a number
if(isalpha(s[i]) || s[i] == '.'){
flag = 0;
break;
}
else flag = 1;
i++;
}
if (flag == 1) return true;
else return false;
}
string RenderProcessTableThread::convertDouble(double value) {
std::ostringstream o;
if (!(o << value))
return "";
return o.str();
}
string RenderProcessTableThread::convertInt(int value) {
std::ostringstream o;
if (!(o << value))
return "";
return o.str();
}
void RenderProcessTableThread::run()
{
forever {
mutex.lock();
mutex.unlock();
fillProcessTable();
sleep(1000);
//cout << "ça marche" << endl;
}
mutex.lock();
if (!restart)
condition.wait(&mutex);
restart = false;
mutex.unlock();
}
void RenderProcessTableThread::setLocalMainWindow(MainWindow& w)
{
localMainWindow = &w;
ui_tableWidgetProcessus = localMainWindow->findChild<QTableWidget*>("tableWidgetProcessus");
ui_tableWidgetProcessus->setColumnCount(11);
ui_tableWidgetProcessus->setColumnWidth(10,508);
QFont fnt;
fnt.setPointSize(10);
fnt.setFamily("Arial");
ui_tableWidgetProcessus->setFont(fnt);
QStringList labels;
labels << "user" << "pid" << "cpu" << "nice" << "vsz" << "rss" << "tty" << "stat" << "start" << "time" << "cmd";
ui_tableWidgetProcessus->setHorizontalHeaderLabels(labels);
}
void RenderProcessTableThread::fillProcessTable() {
QMutexLocker locker(&mutex);
if (!isRunning()) {
start(LowPriority);
} else {
restart = true;
condition.wakeOne();
}
PROCTAB* proc = openproc(PROC_FILLUSR | PROC_FILLMEM | PROC_FILLSTAT | PROC_FILLSTATUS | PROC_FILLARG);
proc_t proc_info;
memset(&proc_info, 0, sizeof(proc_info));
int totalRow = ui_tableWidgetProcessus->rowCount();
for ( int i = 0; i < totalRow ; ++i )
{
ui_tableWidgetProcessus->removeRow(i);
}
int i = 0;
while (readproc(proc, &proc_info) != NULL) {
cout << proc_info.fuser << proc_info.tid << proc_info.cmd << proc_info.resident << proc_info.utime << proc_info.stime << endl;
ui_tableWidgetProcessus->setRowCount(i+1);
ui_tableWidgetProcessus->setItem(i,0,new QTableWidgetItem(QString(proc_info.fuser),0));
ui_tableWidgetProcessus->setItem(i,1,new QTableWidgetItem(QString((char*)convertInt(proc_info.tid).c_str()),0));
ui_tableWidgetProcessus->setItem(i,2,new QTableWidgetItem(QString((char*)convertInt(proc_info.pcpu).c_str()),0));
ui_tableWidgetProcessus->setItem(i,3,new QTableWidgetItem(QString((char*)convertInt(proc_info.nice).c_str()),0));
ui_tableWidgetProcessus->setItem(i,4,new QTableWidgetItem(QString((char*)convertInt(proc_info.vm_size).c_str()),0));
ui_tableWidgetProcessus->setItem(i,5,new QTableWidgetItem(QString((char*)convertInt(proc_info.rss).c_str()),0));
ui_tableWidgetProcessus->setItem(i,6,new QTableWidgetItem(QString((char*)convertInt(proc_info.tty).c_str()),0));
ui_tableWidgetProcessus->setItem(i,7,new QTableWidgetItem(QString(proc_info.state),0));
ui_tableWidgetProcessus->setItem(i,8,new QTableWidgetItem(QString((char*)convertInt(proc_info.start_time).c_str()),0));
ui_tableWidgetProcessus->setItem(i,9,new QTableWidgetItem(QString((char*)convertInt(proc_info.stime).c_str()),0));
//cout << "proc_info.tid : " << proc_info.tid << endl;
//cout << "proc_info.cmdline : " << proc_info.cmdline << endl;
string text;
if (proc_info.cmdline != 0) {
vector<string> v(proc_info.cmdline, proc_info.cmdline + sizeof(proc_info.cmdline) / sizeof(string));
text = v[0];
}
else {
vector<string> v;
v.push_back(proc_info.cmd);
text = v[0];
}
//string text = char_to_string(proc_info.cmdline);
ui_tableWidgetProcessus->setItem(i,10,new QTableWidgetItem(QString((char*)text.c_str()),0));
i++;
}
closeproc(proc);
}
Are they better ways of doing this ?
Thanks
Patrick
This looks like something for Qt's Signal and Slots.
In your case the the thread emits the signal and a slot in your window will be called.
So in your RenderProcessTableThread.h define a signal
signals:
void newValues(const QString &data);
And in your mainwindow.h
public slots:
void showNewValues(const QString &data);
add the data to your table in this slot.
Then you have to connect them (e. g. in the constructor of your mainwindow after the creation of the thread)
connect(yourThread, SIGNAL(newValues(QString)), this, SLOT(showNewValues(QString)));
Whenever you want to show new data, emit the signal (e. g. somewhere in your fillProcessTable() function):
emit newValues(yourValues);
Qt does the connection between the threads for you.