Why does the console stays open although the program is finished? - c++

I'm currently working on a web crawler with the ability to abort at any time when the 'ESC'-button is pressed.
To check whether 'ESC' is pressed, I'm using a thread which sets a flag to signal the 'main'-function to terminate itself. Although this is working fine, the console window doesn't close after the program is finished. The only circumstance under which the console window is closing, is when 'ESC' is pressed immediatly after the thread starts (so before the while loop is starting; see comment in the code).
#include <curl/curl.h>
#include <ctime>
#include <fstream>
#include <iostream>
#include <regex>
#include <queue>
#include <stdio.h>
#include <string>
#include <thread>
#include <vector>
#include <windows.h>
boolean exitCrawler{ false };
char URL[512];
CURL *curl;
int i{ 0 }, start{ 0 }, stop{ 0 }, urlCount{ 0 };
std::ofstream write;
std::deque <const char*> urls;
std::regex rgx("(?:http)[:](?://)[A-Za-z0-9]+.[A-Za-z0-9]+.[a-z]+/");
std::smatch sm;
std::string answer, content;
std::vector <std::string> detectedURLs;
unsigned short keyState;
auto analyzeContent() -> void;
auto crawlSite() -> int;
auto indexSite() -> void;
auto quitCrawler() -> void;
auto writeContent(char*, size_t, size_t)->size_t;
auto main() -> void {
SetConsoleTitle(L"WebCrawler");
write.open("C:\\Users\\Daniel\\Desktop\\urls.txt", std::ios::app);
std::cout << "Welcome to the WebCrawler!" << std::endl << "URL (http://www.*.*/): ";
std::cin >> URL;
std::cout << "Starting to crawl the surface web. Press \"ESC\" at any time to cancel the crawler." << std::endl;
urls.push_back(URL);
std::thread qC(quitCrawler);
qC.detach();
//Press 'ESC' here to get the console window to close itself after the program finishes. If you press 'ESC' after the while loop starts, the console window will stay open.
while (true) {
std::string s(urls.front(), strlen(urls.front()));
if (s.find("http://") == -1) {
urls.pop_front();
content = "";
continue;
}
if (crawlSite() == 1) {
urls.pop_front();
content = "";
continue;
}
analyzeContent();
std::cout << "\rCrawled " << urlCount << " sites of the surface web.";
urls.pop_front();
if ((urls.size() == 0) || exitCrawler) {
break;
}
}
std::cout << std::endl << "Crawler terminating..." << std::endl;
write.close();
}
auto analyzeContent() -> void {
memset(&sm, 0, sizeof(sm));
i = 0;
std::string::const_iterator beginningIterator = content.cbegin();
while (std::regex_search(beginningIterator, content.cend(), sm, rgx)) {
beginningIterator = sm[0].second;
if ((std::find(detectedURLs.begin(), detectedURLs.end(), sm[0])) == detectedURLs.end()) {
urls.push_back(sm[0].str().c_str());
i++;
}
detectedURLs.push_back(sm[0]);
}
}
auto crawlSite() -> int {
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30);
if (curl_easy_setopt(curl, CURLOPT_URL, urls.front()) != CURLE_OK) {
return 1;
}
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &writeContent);
if (curl_easy_perform(curl) != CURLE_OK) {
return 1;
}
curl_easy_cleanup(curl);
curl_global_cleanup();
indexSite();
return 0;
}
auto indexSite() -> void {
urlCount++;
write << " #" << urlCount << "     [" << urls.front() << "]/[...] --- {[...]} --- " << std::time(0) << "<br>" << std::endl;
}
auto quitCrawler() -> void {
keyState = GetAsyncKeyState(VK_ESCAPE);
while (true) {
if (keyState != 0) {
exitCrawler = true;
break;
}
keyState = GetAsyncKeyState(VK_ESCAPE);
}
}
auto writeContent(char* buffer, size_t size, size_t nmemb) -> size_t {
content.append(buffer);
return size * nmemb;
}
To be honest, I do not have any clue why the program is staying open after the code is finished.Does anybody of you have any idea?

Related

How to manipulate libevent bufferevents outside of callbacks

I use libevent to write client-server application, on client side i want to continiusly wait for intput from console. I tried to run event_base_dispatch in thread, and in main thread ask for input string and add it to bufferevent.
std::thread libevthr(libev_start, base);
std::string s;
do
{
cin >> s;
bufferevent_write(bev, "Hello, world!", 13);
} while(s != "xxx");
libevthr.join();
For some reason this doesn't work, but if i put bufferevent_write inside one of callbacks, it works fine
void event_cb(struct bufferevent *bev, short events, void *ptr)
{
if (events & BEV_EVENT_CONNECTED) {
/* We're connected to 127.0.0.1 Ordinarily we'd do
something here, like start reading or writing. */
bufferevent_write(bev, "Hello, world!", 13);
std::cout << "Connected" << std::endl;
}
if (events & BEV_EVENT_ERROR) {
if (EVUTIL_SOCKET_ERROR() == 10054)
cout << "Server stopped working!" << endl;
else
cout << "Error has happened" << endl;
}
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR))
{
bufferevent_free(bev);
}
}
Can you explain how should i write this correctly?
Sorry if i have any mistakes in english.
Full code here:
#include "UClient.h"
#include <iostream>
#include "event2/event.h"
#include "event2/listener.h"
#include "event2/bufferevent.h"
#include "event2/buffer.h"
#include <thread>
using std::cout, std::cin, std::endl;
void event_cb(struct bufferevent *bev, short events, void *ptr)
{
if (events & BEV_EVENT_CONNECTED) {
/* We're connected to 127.0.0.1 Ordinarily we'd do
something here, like start reading or writing. */
bufferevent_write(bev, "Hello, world!", 13);
std::cout << "Connected" << std::endl;
}
if (events & BEV_EVENT_ERROR) {
if (EVUTIL_SOCKET_ERROR() == 10054)
cout << "Server stopped working!" << endl;
else
cout << "Error has happened" << endl;
}
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR))
{
bufferevent_free(bev);
}
}
void write_cb(struct bufferevent *bev, void *ctx)
{
cout << 'Data was written' << endl;
}
void libev_start(event_base *base)
{
event_base_dispatch(base);
}
int main()
{
int port = 9554;
struct event_base *base;
struct bufferevent *bev;
struct sockaddr_in cl_inf;
if (!initWinsock()) {
perror("Failed to initialize Winsock");
return 1;
}
base = event_base_new();
ZeroMemory(&cl_inf, sizeof(cl_inf));
in_addr serv_ip;
inet_pton(AF_INET, "127.0.0.1", &serv_ip);
cl_inf.sin_family = AF_INET;
cl_inf.sin_addr = serv_ip;
cl_inf.sin_port = htons(port);
bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, NULL, write_cb, event_cb, NULL);
if (bufferevent_socket_connect(bev,
(struct sockaddr *)&cl_inf, sizeof(cl_inf)) < 0) {
/* Error starting connection */
std::cout << "Can't connect to server!" << std::endl;
bufferevent_free(bev);
return -1;
}
bufferevent_enable(bev, EV_READ | EV_WRITE);
std::thread libevthr(libev_start, base);
std::string s;
do
{
cin >> s;
} while(s != "xxx");
libevthr.join();
std::cout << "client finished working";
return 0;
}

How do I make it so no matter how many times the user presses enter with a blank string, it always prints the 'start' string?

This is my code -
How do I make this loop unlimited?
Like any terminal when you press enter with a blank string it rewrites your root
#include <iostream>
#include <windows.h>
std::string input_t;
void startup(std::string start) {
std::cout << start;
while(true) {
while ( n = std::cin.get() ) {
if ( int n == (int)'\n' ) {
std::cout << start;
std::cin >> input_t;
}
else {
std::cout << "Program is terminating...\n";
exit(EXIT_FAILURE);
}
}
}
}
int main() {
startup("User:DESKTOP$ ");
std::cin.get();
}
You can use std::getline to keep reading in strings up to a newline:
while(std::getline(std::cin, input_t))
{
if (line.empty())
{
std::cout << start;
continue;
}
// else do stuff with input_t, or break
}

state is "downloading", but torrent_file() returns NULL?

I recently tried to write a scraper capable of downloading 3.5 million
torrent files based on their magnet URL. I decided to start by hacking
an example from libtorrent's tutorial webpage, but while it works well
with just one torrent file, it fails segfaults in create_torrent() when
I try to download more than one file. Here's my code:
#include <thread>
#include <chrono>
#include <fstream>
#include <sstream>
#include <string>
#include <libtorrent/session.hpp>
#include <libtorrent/add_torrent_params.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/torrent_handle.hpp>
#include <libtorrent/alert_types.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/torrent_status.hpp>
#include <libtorrent/torrent_info.hpp>
namespace lt = libtorrent;
using clk = std::chrono::steady_clock;
int torrents_left = 0;
int save_file(std::string const& filename, std::vector<char>& v)
{
FILE* f = std::fopen(filename.c_str(), "wb");
if (f == nullptr)
return -1;
int w = int(std::fwrite(&v[0], 1, v.size(), f));
std::fclose(f);
if (w < 0) return -1;
if (w != int(v.size())) return -3;
return 0;
}
void add_torrent_url(std::string url, lt::session& ses) {
// std::cerr << "DEBUG: Will download '" << url << "'" << std::endl;
lt::add_torrent_params atp;
atp.url = url;
atp.save_path = "."; // save in current dir
ses.async_add_torrent(atp);
torrents_left++;
}
void add_torrents_from_stdin(lt::session& ses) {
std::cerr << "DEBUG: reading stdin." << std::endl;
std::string url;
while(std::getline(std::cin, url)) {
add_torrent_url(url, ses);
}
std::cerr << "DEBUG: done reading stdin." << std::endl;
}
int main(int argc, char const* argv[])
{
lt::settings_pack pack;
pack.set_int(lt::settings_pack::alert_mask
, lt::alert::error_notification
| lt::alert::storage_notification
| lt::alert::status_notification);
lt::session ses(pack);
lt::add_torrent_params atp;
//add_torrent_url(argv[1]);
add_torrent_url("magnet:?xt=urn:btih:3E37CFE29B1049E03F858758A73EFD85BA170BE8", ses);
add_torrent_url("magnet:?xt=urn:btih:8FCDE178E3F9A24EA40856826C4E8A625A931B73", ses);
//add_torrents_from_stdin(ses);
// this is the handle we'll set once we get the notification of it being
// added
lt::torrent_handle h;
for (;;) {
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
for (lt::alert const* a : alerts) {
if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
h = at->handle;
}
// if we receive the finished alert or an error, we're done
if (lt::alert_cast<lt::torrent_finished_alert>(a)) {
std::cout << "torrent finished or error." << std::endl;
goto done;
}
if (lt::alert_cast<lt::torrent_error_alert>(a)) {
std::cout << a->message() << std::endl;
goto done;
}
if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
if (st->status.empty()) continue;
// we only have a single torrent, so we know which one
// the status is for
lt::torrent_status const& s = st->status[0];
if (s.state == lt::torrent_status::downloading)
{
std::cout << "Hi!" << std::endl;
std::shared_ptr<const lt::torrent_info> ti = h.torrent_file();
if (ti == 0) {
std::cerr << "ERROR: ti == NULL" << std::endl;
goto done;
}
ses.remove_torrent(h, lt::session::delete_files);
lt::create_torrent new_torrent(*ti);
std::vector<char> out;
lt::bencode(std::back_inserter(out), new_torrent.generate());
std::stringstream ss;
ss << "downloaded/" << (*ti).info_hash() << ".torrent";
save_file(ss.str(), out);
h.pause();
torrents_left--;
std::cerr << "DEBUG: Done (" << torrents_left << " left): " << (*ti).info_hash() << std::endl;
if (torrents_left == 0)
goto done;
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// ask the session to post a state_update_alert, to update our
// state output for the torrent
ses.post_torrent_updates();
}
done:
{}
}
I suspect it's related to this part:
// we only have a single torrent, so we know which one
// the status is for
lt::torrent_status const& s = st->status[0];
But according to my debugger, when torrent_file() gives NULL, st->status[] only contains one element anyway.
What's happening here? How do I fix it?
It looks like I made wrong assumptions about what "h" points to in the example. Here's a diff that fixes the code in question:
--- scrape_rasterbar.cpp 2017-01-07 21:00:39.565636805 +0100
+++ scrape_rasterbar_old.cpp 2017-01-07 21:05:53.339718098 +0100
## -1,4 +1,3 ##
-#include <iostream>
#include <thread>
#include <chrono>
#include <fstream>
## -94,17 +93,18 ##
if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
if (st->status.empty()) continue;
- for (auto &s : st->status) {
// we only have a single torrent, so we know which one
// the status is for
+ lt::torrent_status const& s = st->status[0];
if (s.state == lt::torrent_status::downloading)
{
- std::shared_ptr<const lt::torrent_info> ti = s.handle.torrent_file();
+ std::cout << "Hi!" << std::endl;
+ std::shared_ptr<const lt::torrent_info> ti = h.torrent_file();
if (ti == 0) {
std::cerr << "ERROR: ti == NULL" << std::endl;
goto done;
}
- ses.remove_torrent(s.handle, lt::session::delete_files);
+ ses.remove_torrent(h, lt::session::delete_files);
lt::create_torrent new_torrent(*ti);
std::vector<char> out;
lt::bencode(std::back_inserter(out), new_torrent.generate());
## -112,7 +112,7 ##
std::stringstream ss;
ss << "downloaded/" << (*ti).info_hash() << ".torrent";
save_file(ss.str(), out);
- s.handle.pause();
+ h.pause();
torrents_left--;
std::cerr << "DEBUG: Done (" << torrents_left << " left): " << (*ti).info_hash() << std::endl;
if (torrents_left == 0)
## -120,7 +120,6 ##
}
}
}
- }
std::this_thread::sleep_for(std::chrono::milliseconds(200));
// ask the session to post a state_update_alert, to update our

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;
}

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.