I am trying to create a tunnel and car threads that simulate a tunnel that only goes one way. Lets say each way is W and B. The way to W is open for 5 seconds, then the tunnel is closed for another 5, then the tunnel is open for way B for 5 seconds and then closed for another 5, then repeat.
I have created the tunnel thread with the tunnelf function but it does not do anything but print the first line: "The tunnel is now open to Whittier Bound traffic". And it only does that sometimes. Each time i compile the code, it can either print nothing or that line. It does not go through the required outputs. Meanwhile if i put the exact same while loop from the tunnelf thread into main, it works
#include <iostream>
#include <cstring>
#include <string>
#include <cctype>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <pthread.h>
#include <conio.h>
#include <windows.h>
#include <ctime>
#include <cerrno>
#include <unistd.h>
using namespace std;
void *car(void *arg);
void *tunnelf();
static pthread_mutex_t traffic_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t car_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t bbcan = PTHREAD_COND_INITIALIZER;
static pthread_cond_t wbcan =PTHREAD_COND_INITIALIZER;
static pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;
static bool whittierBound = false;
static bool bbBound = false;
struct car2{
int arrive;
int cross;
string bound;
};
int main(){
ifstream in;
in.open("Thrd.txt");
if (in.fail()){
cout<< "failed to open file";
exit(1);
}
car2 record[50];
int max_cars;
int arrive;
int cross;
string bound;
string data;
int i = 0;
in >> max_cars;
cout<<"Num cars "<<max_cars<<endl;
while(!in.eof()){
in >> record[i].arrive >>record[i].bound >> record[i].cross;
i++;
}
int size = i;
for(int i= 0; i<size; i++){
cout << record[i].arrive <<record[i].bound <<record[i].cross<<endl;
}
pthread_t cartid[max_cars];
pthread_t tunnel;//just shared variable for the tunnel
pthread_create(&tunnel, NULL, &tunnelf, NULL);
in.close();
}
void *tunnelf(){
static int done;
while(done==0){
pthread_mutex_lock(&traffic_lock);
whittierBound = true;
cout << "The tunnel is now open to Whiitier-bound traffic"<<endl;
pthread_cond_broadcast(&wbcan);
pthread_mutex_unlock(&traffic_lock);
sleep(5);
pthread_mutex_lock(&traffic_lock);
whittierBound = false;
cout << "The tunnel is now closed to all traffic"<<endl;
pthread_mutex_unlock(&traffic_lock);
sleep(5);
pthread_mutex_lock(&traffic_lock);
bbBound = true;
cout << "The tunnel is now open to Bear-Valley-bound traffic"<<endl;
pthread_cond_broadcast(&bbcan);
pthread_mutex_unlock(&traffic_lock);
sleep(5);
pthread_mutex_lock(&traffic_lock);
bbBound = false;
cout << "The tunnel is now closed to all traffic"<<endl;
pthread_mutex_unlock(&traffic_lock);
}
}
One thing to mention, you never guard against array overruns. In C++17, you can use std::size. You might consider using std::array for record, which would help in debug builds (but not release)
while(!in.eof() && i<std::size(record)){
in >> record[i].arrive >>record[i].bound >> record[i].cross;
// cout <<arrive<<" " << bound<<" " << cross<<endl;
i++;
}
Related
Im trying to make multithreaded proxy checker in c++, when I start the threads and lock it all threads wait till the request is finished. I tried to remove the locks but that doesn't help either. Im using the cpr library to make the requests, the documentation can be found here: https://whoshuu.github.io/cpr/advanced-usage.html.
Reproduceable example:
#include <stdio.h>
#include <pthread.h>
#include <iostream>
#include <queue>
#include <mutex>
#include <cpr/cpr.h>
#include <fmt/format.h>
#define NUMT 10
using namespace std;
using namespace fmt;
std::mutex mut;
std::queue<std::string> q;
void* Checker(void* arg) {
while (!q.empty()) {
mut.lock();
//get a webhook at https://webhook.site
string protocol = "socks4";
string proxyformatted = format("{0}://{1}", protocol, q.front());
auto r = cpr::Get(cpr::Url{ "<webhook url>" },
cpr::Proxies{ {"http", proxyformatted}, {"https", proxyformatted} });
q.pop();
mut.unlock();
}
return NULL;
}
int main(int argc, char** argv) {
q.push("138.201.134.206:5678");
q.push("185.113.7.87:5678");
q.push("5.9.16.126:5678");
q.push("88.146.196.181:4153");
pthread_t tid[NUMT]; int i;
int thread_args[NUMT];
for (i = 0; i < NUMT; i++) {
thread_args[i] = i;
pthread_create(&tid[i], NULL, Checker, (void*) &thread_args);
}
for (i = 0; i < NUMT; i++) {
pthread_join(tid[i], NULL);
fprintf(stderr, "Thread %d terminated\n", i);
}
return 0;
}
Thanks in advance.
I suggest to implement a wrapper class for your queue that will hide the mutex.
That class can provide push(std::string s) and bool pop(std::string& s) that returns true and populate s if the queue wasn't empty or false othervise. Then your worker threads can simply loop
std::string s;
while(q.pop(s)) {
...
}
I have simplified my code, and it compiles, but it doesn't do anything. It doesn't error out though either. I am trying to get 7 threads (on my 8-core processor) in this example to write to a variable to benchmark my system. I would like to do this with multiple threads to see if it's faster. It's based off other code that worked before I added multithreading. When I run, it just terminates. It should show progress each second of how many total iterations all the threads have done together. Some of the includes are there from other code I am working on.
I would like to also gracefully terminate all 7 threads when Ctrl-C is pressed. Help would be appreciated. Thanks!
//Compiled using: g++ ./test.cpp -lpthread -o ./test
#include <stdio.h>
#include <string>
#include <iostream>
#include <time.h>
#include <ctime>
#include <ratio>
#include <chrono>
#include <iomanip>
#include <locale.h>
#include <cstdlib>
#include <pthread.h>
using namespace std;
using namespace std::chrono;
const int NUM_THREADS = 7;
const std::string VALUE_TO_WRITE = "TEST";
unsigned long long int total_iterations = 0;
void * RunBenchmark(void * threadid);
class comma_numpunct: public std::numpunct < char > {
protected: virtual char do_thousands_sep() const {
return ',';
}
virtual std::string do_grouping() const {
return "\03";
}
};
void * RunBenchmark(void * threadid) {
unsigned long long int iterations = 0;
std::string benchmark;
int seconds = 0;
std::locale comma_locale(std::locale(), new comma_numpunct());
std::cout.imbue(comma_locale);
auto start = std::chrono::system_clock::now();
auto end = std::chrono::system_clock::now();
do {
start = std::chrono::system_clock::now();
while ((std::chrono::duration_cast < std::chrono::seconds > (end - start).count() != 1)) {
benchmark = VALUE_TO_WRITE;
iterations += 1;
}
total_iterations += iterations;
iterations = 0;
cout << "Total Iterations: " << std::setprecision(0) << std::fixed << total_iterations << "\r";
} while (1);
}
int main(int argc, char ** argv) {
unsigned long long int iterations = 0;
int tc, tn;
pthread_t threads[NUM_THREADS];
for (tn = 0; tn < NUM_THREADS; tn++) {
tc = pthread_create( & threads[tn], NULL, & RunBenchmark, NULL);
}
return 0;
}
Sorry for my english, if something is not clear, please ask me. I am having trouble to make that application for WindowsForms ("ThreadTeste" is a representation of "MyForm1"):
#include <chrono>
#include <iostream>
#include <thread>
using namespace std;
using namespace std::chrono;
class ThreadTeste
{
public:
void loop()
{
for(int i = 0 ; i < 5 ; i++)
{
cout << i << endl;
this_thread::sleep_for(seconds(1));
}
}
thread getThread()
{
return thread(&ThreadTeste::loop, this);
}
ThreadTeste()
{
thread myThread = getThread();
myThread.detach();
}
};
int main(int argc, char *argv[])
{
ThreadTeste* t = new ThreadTeste();
while(true)
{
cout << "Working" << endl;
this_thread::sleep_for(seconds(1));
}
}
//That works!!
D:
If you want to output from 0 to 4 and then output working, then you could not use detach. Because detach means that the main thread does not need to wait for the execution of the child thread to complete and the two are out of relationship,then it will run by itself.
You could use join.
ThreadTeste()
{
thread myThread = getThread();
myThread.join();
}
In my main program I am copying a string buffer into a boost ring buffer and then trying to consume that data in a created thread and writing to a file. In the main thread also I am writing the same data to a file but both input and output file is not matching.
I feel I am doing something incredibly stupid. Please help. Also, if there are any suggesting to improve the code that would really be appreciated.
#include <iostream>
#include <vector>
#include <boost/circular_buffer.hpp>
#include <numeric>
#include <assert.h>
#include <thread>
#include <mutex>
#include <chrono>
#include <time.h>
#include <cstdint>
#include <fstream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::fstream;
using std::string;
#define SOME_FIXED_HARDCODED_NUMBER 40980
class MyClass {
public:
std::vector<int8_t> vec;
public:
MyClass(std::vector<int8_t> v){ vec = v; }
};
boost::circular_buffer<MyClass> cb(300);
int waiting = 1;
std::mutex my_mutex;
FILE *out_file;
FILE *in_file;
void foo()
{
while (waiting) {
std::unique_lock<std::mutex> lock(my_mutex);
if (!cb.size() || waiting == 0) {
lock.unlock();
continue;
}
if (!waiting)
break;
MyClass local_buf = cb.front();
cb.pop_front();
fwrite(local_buf.vec.data(), 1, local_buf.vec.size(), out_file);
}
}
int main(int argc, char* argv[])
{
out_file = fopen("output_data.raw", "w");
in_file = fopen("input_data.raw", "w");
std::thread th1(foo);
char *buf = {"abc"};
int counter = 0;
std::vector<int8_t> mem;
mem.insert(mem.end(), buf, buf + strlen(buf));
while (counter < SOME_FIXED_HARDCODED_NUMBER)
{
{
std::unique_lock<std::mutex> lock(my_mutex);
/* if the circular buffer is full then wait for consumer to pull the data */
while (cb.full()) {
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::unique_lock<std::mutex> lock(my_mutex);
}
cb.push_front(MyClass(mem));
fwrite(mem.data(), 1, mem.size(), in_file);
}
counter++;
}
waiting = 0;
th1.join();
fclose(out_file);
fclose(in_file);
return 0;
}
while (cb.full()) {
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
>>> std::unique_lock<std::mutex> lock(my_mutex);
}
The marked unique_lock doesn't do anything as it will go out of scope immediately and unlock the mutex. Hence once you leave the loop the mutex is not locked and you have a racecondition. Instead, you should use lock.lock() to relock the mutex.
There is a few more bugs. You are not waiting for your foo thread to actually drain the buffer. It will stop as soon as the waiting flag is set by the main thread. Also, waiting should be an atomic.
Here is my simple code, I want to get in the console_task, the value of the variable i in the dialer_task... without using a global variable.
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include "console.hpp"
using namespace std;
void console_task(){
console();
}
void dialer_task(){
int i=0;
while (1) {
printf("LOOP %d\n",i);
i++;
sleep(5);
}
}
int main()
{
thread t1(console_task);
thread t2(dialer_task);
t1.join();
t2.join();
return 0;
}
The constraint that there may not be a global variable to share the state between the threads leaves essentially 2 viable alternatives;
Allocate the shared state on the heap and pass that on to the threads
Allocate the shared state on the original thread's stack and "feed" it to the worker threads for shared use.
The catch to both solutions is to make sure that the access is appropriately guarded or atomic.
A simple solution is to use an std::atomic and share the reference between the threads.
#include <type_traits>
#include <thread>
#include <atomic>
#include <iostream>
void console_task(std::atomic_int& j) {
using namespace std;
int i = 0;
while (++i < 50) {
cout << "task " << j << endl; // uncontrolled access to the console (demo)
std::chrono::microseconds delay{50};
this_thread::sleep_for(delay);
}
}
void dialer_task(std::atomic_int& j){
using namespace std;
int i = 0;
while ( ++i < 10) {
//cout << "LOOP " << i << endl; // uncontrolled access to the console (demo)
std::chrono::microseconds delay{145};
this_thread::sleep_for(delay);
j = i;
}
}
int main()
{
std::atomic_int i { 0 };
std::thread t1( console_task, std::ref(i));
// a lambda with reference capture could also be used
// std::thread t1( [&](){console_task(i);} );
std::thread t2( dialer_task, std::ref(i));
t1.join();
t2.join();
return 0;
}
There is a catch to the shared atomic, it needs to remain valid for the duration of the threads (as it does here).
Demo code.
Further heap based alternatives can be considered; e.g. using a shared std::mutex together with a std::shared_ptr.