i making class event manager like below
EventManager.h
#ifndef EVENTMANAGER_H
#define EVENTMANAGER_H
#include <thread>
#include <mutex>
#include <chrono>
#include <atomic>
#include <condition_variable>
#include <vector>
#include "../../object/EObject.h"
class EventManager : public EObject {
public:
EventManager();
virtual ~EventManager();
int start_event();
void stop_event();
void add(const char* name, int interval, EObject * instance);
private:
static const int MAX_EVENT = 10;
std::atomic<int> event_total;
struct {
int event_id;
std::string event_name;
int interval;
std::atomic<bool> next_execute;
EObject * instance;
std::unique_ptr<std::condition_variable> cv;
std::unique_ptr<std::mutex> mtx;
} my_event[MAX_EVENT];
std::thread * event_thread;
std::atomic<bool> shall_stop;
std::atomic<bool> has_stopped;
std::atomic<int> worker_delay;
void worker();
//timing
std::vector<std::unique_ptr<std::thread>> timing_work;
void timing(int id);
};
#endif /* EVENTMANAGER_H */
EventManager.cpp
#include <iostream>
#include "EventManager.h"
#include "../../object/EVariant.h"
using namespace std;
EventManager::EventManager() {
event_thread = nullptr;
has_stopped = true;
shall_stop = false;
worker_delay = 5; //milli second
event_total = 0;
}
EventManager::~EventManager() {
}
int EventManager::start_event() {
if (event_thread) {
cout << "Event thread can not create\n" << flush;
return -1;
} else {
event_thread = new std::thread([this] {
this->worker();
});
cout << "Event thread created\n" << flush;
}
return 0;
}
void EventManager::stop_event() {
shall_stop = true;
for (int i = 0; i < 5; i++) {
this_thread::sleep_for(chrono::microseconds(10));
if (has_stopped) break;
}
delete event_thread;
event_thread = nullptr;
}
void EventManager::worker() {
has_stopped = false;
while (1) {
if (shall_stop) break;
for (int i = 0; i < event_total; i++) {
// cout << "Event Manager: " << my_event[i].event_name << " - checking \n" << flush;
if (my_event[i].next_execute) {
EVariant var = EVariant();
var.push("event_name", my_event[i].event_name);
my_event[i].instance->update(var);
my_event[i].next_execute = false;
{
condition_variable * cv = my_event[i].cv.get();
mutex * mtx = my_event[i].mtx.get();
unique_lock<mutex> lock(*mtx);
cv->notify_one();
// cout << "Event Manager: " << my_event[i].event_name << " - hey wakeup \n" << flush;
}
}
}
this_thread::sleep_for(chrono::milliseconds(worker_delay));
}
shall_stop = false;
has_stopped = true;
}
void EventManager::timing(int id) {
int _id = id;
cout << "Timing thread: " << my_event[_id].event_name << " - " << this_thread::get_id() << " - i was born\n" << flush;
while (1) {
int delay = my_event[_id].interval;
// cout << "Event Manager: " << my_event[_id].event_name << " - i delay \n" << flush;
this_thread::sleep_for(chrono::milliseconds(delay));
my_event[_id].next_execute = true;
{
// cout << "Event Manager: " << my_event[_id].event_name << " - i sleep \n" << flush;
condition_variable * cv = my_event[_id].cv.get();
mutex * mtx = my_event[_id].mtx.get();
unique_lock<mutex> lock(*mtx);
cv->wait(lock);
// cout << "Event Manager: " << my_event[_id].event_name << " - OK wakeup \n" << flush;
}
}
cout << "Timing thread: " << id << " - i'm quit\n" << flush;
}
void EventManager::add(const char* name, int interval, EObject* instance) {
cout << "Event adding : " << name << "\n" << flush;
event_total += 1;
int id = event_total - 1;
my_event[id].event_id = id;
my_event[id].event_name = name;
my_event[id].interval = interval;
my_event[id].instance = instance;
my_event[id].next_execute = false;
unique_ptr<mutex> mtx(new mutex());
my_event[id].mtx = std::move(mtx);
unique_ptr<condition_variable> cov(new condition_variable());
my_event[id].cv = std::move(cov);
//create thread delay
// std::thread th([this] {
// this->timing(event_total - 1);
// });
unique_ptr<thread> thd(new thread([this] {
this->timing(event_total - 1);
}));
// timing_collection.push_back(std::move(th));
timing_work.push_back(std::move(thd));
}
Calling
//event i2c communication
p_event_manager.emplace("I2C", new EventManager());
p_event_manager.at("I2C")->add("i2c_buffer", 10, pI2c.at("i2c-1"));
p_event_manager.at("I2C")->add("i2c_poll_tb", 30, p_touch_button.at("TouchButton1"));
p_event_manager.at("I2C")->add("i2c_micro_poll", 50, bsc_app);
p_event_manager.at("I2C")->start_event();
Algorithm:
When add function called, the function will add the struct and create new thread for delay cycle, the thread will move to vector, the thread will change flag of event for next execute on event main thread.
The problem:
The problem is often that the thread for delay is not successful created, so the event is not called. How to fix it?
Using this_thread::sleep_for() inside a timer function is not advisable, and you are likely to miss a trigger point during the sleep cycle. Excessive polling for the trigger point will also result in unnecessary wasted of CPU cycles. So you should rely mainly on condition_variables that trigger at the exact time without polling.
For example you can push a std::pair<time_point,thread_id> in an ordered container sorted in chronological order. Also see if priority queue could suit your needs. Your routine is overly complicated, simplicity has its own quality.
Related
This should be a normal timer that runs until it's either paused or exited. The code is exited by the NextStep() Function. And The timer is supposed to pause and stay paused until it's pressed again.
However, when I press the spacebar, the timer stops only after adding another digit to the timer.
An example of the problem:
01sec
02sec
I press the spacebar.
03sec (+1sec)
The timer pauses.
On the other hand, the code that executes the NextStep() works fine without any delays.
I tried rewriting it in different ways, but none of them worked.
#pragma once
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include <stdlib.h>
#include <iomanip>
#include <math.h>
#include <windows.h>
#include <conio.h>
#include <thread>
using namespace std;
void NextStep();
bool pause = false;
bool stop = false;
void wait(int milliseconds)
{
int counter = 0;
while (pause) {
char ch = _getch();
if (ch == ' ')
{
pause = !pause;
}
else if (ch == 27)
{
cout << "\033c";
NextStep();
stop = true;
}
}
while (counter < milliseconds && !stop)
{
if (pause) {
continue;
}
if (pause == false) {
this_thread::sleep_for(chrono::milliseconds(1));
counter++;
}
}
}
void timer()
{
int seconds = 0;
int minutes = 0;
int hours = 0;
while (true)
{
cout << "\033c";
cout << setfill(' ') << setw(55) << " Timer \n";
cout << " ";
cout << setfill('0') << setw(2) << hours << "h ";
cout << setfill('0') << setw(2) << minutes << "min ";
cout << setfill('0') << setw(2) << seconds << "sec ";
wait(60);
seconds++;
if (seconds == 60) {
minutes++;
seconds = 0;
}
else if (minutes == 60)
{
hours++;
minutes = 0;
seconds = 0;
}
if (_kbhit())
{
char ch = _getch();
if (ch == ' ')
{
pause = !pause;
}
else if (ch == 27)
{
cout << "\033c";
NextStep();
stop = true;
break;
}
}
}
}
Here's the NextStep() function:
void NextStep()
{
string option;
correct = false;
cout << "\033c";
cout << "Loading...";
Sleep(1300);
cout << "\033c";
cout << "What would you like to do next?" << endl;
cout << "" << endl;
cout << "To change your password TYPE: password" << endl;
cout << "To use a calculator TYPE: calculator" << endl;
cout << "To use a timer TYPE: timer" << endl;
cout << "" << endl;
cout << "Type your choice: ";
UserInput();
}
I'm not sure I understand all the workings of your code, but I think I understand that you need to have a timer that can be started, paused, and restarted. Also if I understood correctly the timer should not be affected (= paused) by the fact that the thread is in sleep.
So, here is an implementation of such a timer that might help you (at least for part of your problem) :
#include <chrono>
template<typename T>
class Timer
{
public:
void start()
{
m_start = std::chrono::steady_clock::now();
}
void pause()
{
m_elapsed += get_current_elapsed();
m_start = {};
}
void reset()
{
m_start = {};
m_elapsed = {};
}
int64_t get_elapsed()
{
return (m_elapsed + get_current_elapsed()).count();
}
private:
std::chrono::time_point<std::chrono::steady_clock> m_start{};
T m_elapsed{};
bool is_started()
{
return m_start.time_since_epoch() != T{};
}
T get_current_elapsed()
{
return is_started() ? std::chrono::duration_cast<T>(std::chrono::steady_clock::now() - m_start) : T{};
}
};
And here is an example of how it can be used :
#include <iostream>
#include <thread>
int main()
{
Timer<std::chrono::seconds> timer;
timer.start();
std::this_thread::sleep_for(std::chrono::seconds(1));
timer.pause(); // "optional"
std::cout << timer.get_elapsed() << std::endl; // 1
timer.start(); // "optional"
std::this_thread::sleep_for(std::chrono::seconds(1));
timer.pause(); // "optional"
std::cout << timer.get_elapsed() << std::endl; // 2
timer.reset();
timer.start();
std::this_thread::sleep_for(std::chrono::seconds(1));
timer.pause(); // "optional"
std::cout << timer.get_elapsed() << std::endl; // 1
return 0;
}
Timer is a template, so instead of std::chrono::seconds you can use any of the following types depending on the precision you want for the timer :
std::chrono::nanoseconds
std::chrono::microseconds
std::chrono::milliseconds
std::chrono::seconds
std::chrono::minutes
std::chrono::hours
std::chrono::days
std::chrono::years
I have a class called "Vector", which by default holds 10.000 elements, which at all times must have the same value. This class is tested and works. Therefore I use the method setAndTest() from the class to set the value of all elements, which then immediately checks whether the Vector object is consistent (that all vector elements hold the same value).
In a new file "main.cpp", i have created two functions: writer() and main().
writer() creates a user-defined number of writer threads (between 1 & 100), each with their own unique id. Each writer sets and tests the shared Vector object to its id every second. If a writer detects an inconsistensy in a shared Vector object, setAndTest() returns false and the following error message should be printed: Error with thread #id
However, in 99% of the cases it prints Success with thread #id, whereas I expected that there would be more variation between the two.
Headers included in main.cpp file:
#include <iostream>
#include "Vector.hpp"
#include <pthread.h>
#include <unistd.h>
using namespace std;
Vector object and writer() function:
Vector VecObj; //The Vector object (Defined in global scope)
void* writer(void *threadid)
{
int threadid_ = *(int *)(threadid);
if(VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << endl;
}else
{
std::cout << "\nError with thread " << threadid_ << endl;
}
return NULL;
}
main function:
int main()
{
start:
int numOfThreads = 1;
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if(0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << endl;
}else{
std::cout << "Amount of threads must be between 1 & 100" << endl;
goto start;
}
pthread_t threadcreator[numOfThreads];
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, &i);
sleep(1);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
}
Vector Class (Vector.hpp):
#ifndef VECTOR_HPP_
#define VECTOR_HPP_
#include <pthread.h>
using namespace std;
//=======================================================
// Class: Vector
// contains a size_-size vector of integers.
// Use the function setAndTest to set all elements
// of the vector to a certain value and then test that
// the value is indeed correctly set
//=======================================================
class Vector
{
public:
Vector(unsigned int size = 10000) : size_(size)
{
vector_ = new int[size_];
set(0);
}
~Vector()
{
delete[] vector_;
}
bool setAndTest(int n)
{
set(n);
return test(n);
}
private:
void set(int n)
{
for(unsigned int i=0; i<size_; i++) vector_[i] = n;
}
bool test(int n)
{
for(unsigned int i=0; i<size_; i++) if(vector_[i] != n) return false;
return true;
}
int* vector_;
unsigned int size_;
};
#endif
You are passing each thread a pointer to the same int variable. That variable changes value on each loop iteration. writer() is expecting to receive the same int value that was given to pthread_create(), but that is not guaranteed in your code, even with the sleep() call.
To pass the int correctly, pass the actual int value itself rather than a pointer to the int, eg:
#include <iostream>
#include <vector>
#include <cstdint>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = static_cast<int>(reinterpret_cast<intptr_t>(arg));
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, reinterpret_cast<void*>(i));
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
If you really want to use int* pointers, then you will have to allocate a separate int for each thread, eg:
#include <iostream>
#include <vector>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = *static_cast<int*>(arg);
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
std::vector<int> threadids(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
threadids[i] = i;
pthread_create(&threadcreator[i], NULL, writer, &threadids[i]);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
Or, if you really want to pass an int* pointer to a single int, use a std::conditional_variable or other waitable signal to make sure that each thread has actually captured the int value before allowing the loop to change its value, eg:
#include <iostream>
#include <vector>
#include <conditional_variable>
#include <mutex>
#include "Vector.hpp"
#include <pthread.h>
Vector VecObj;
std::condition_variable cv;
std::mutex cv_m;
bool captured = false;
void* writer(void *arg)
{
int threadid_;
{
std::lock_guard<std::mutex> lk(cv_m);
threadid_ = *static_cast<int*>(arg);
captured = true;
}
cv.notify_one();
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
std::unique_lock<std::mutex> lk(cv_m);
captured = false;
pthread_create(&threadcreator[i], NULL, writer, &i);
cv.wait(lk, [](){ return captured; });
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
UPDATE: oh, now I see another major problem. You have multiple threads writing to, and reading from, a single Vector object in memory without synchronization. That is not safe to do. While one thread is reading from an element in the Vector's array, another thread can be writing a new value to that same element, and there is no guarantee that the element will remain consistent across both operations. You MUST synchronize access to the Vector object since it is being shared across multiple threads, eg:
...
#include <mutex>
...
Vector VecObj;
std::mutex vec_m;
...
void* writer(void *threadid)
{
int threadid_ = ...;
bool testResult;
{
std::lock_guard lk(vec_m);
testResult = VecObj.setAndTest(threadid_);
}
if (testResult)
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
...
I saw this example as part of the TinyThread c++ library and noticed how it is incrementing gCount on a secondary thread, and then being printed by the main thread. See test 5
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#include <iostream>
#include <list>
#include <tinythread.h>
#include <fast_mutex.h>
using namespace std;
using namespace tthread;
// HACK: Mac OS X and early MinGW do not support thread-local storage
#if defined(__APPLE__) || (defined(__MINGW32__) && (__GNUC__ < 4))
#define NO_TLS
#endif
// Thread local storage variable
#ifndef NO_TLS
thread_local int gLocalVar;
#endif
// Mutex + global count variable
mutex gMutex;
fast_mutex gFastMutex;
int gCount;
// Condition variable
condition_variable gCond;
// Thread function: Thread ID
void ThreadIDs(void * aArg)
{
cout << " My thread id is " << this_thread::get_id() << "." << endl;
}
#ifndef NO_TLS
// Thread function: Thread-local storage
void ThreadTLS(void * aArg)
{
gLocalVar = 2;
cout << " My gLocalVar is " << gLocalVar << "." << endl;
}
#endif
// Thread function: Mutex locking
void ThreadLock(void * aArg)
{
for(int i = 0; i < 10000; ++ i)
{
lock_guard<mutex> lock(gMutex);
++ gCount;
}
}
// Thread function: Mutex locking
void ThreadLock2(void * aArg)
{
for(int i = 0; i < 10000; ++ i)
{
lock_guard<fast_mutex> lock(gFastMutex);
++ gCount;
}
}
// Thread function: Condition notifier
void ThreadCondition1(void * aArg)
{
lock_guard<mutex> lock(gMutex);
-- gCount;
gCond.notify_all();
}
// Thread function: Condition waiter
void ThreadCondition2(void * aArg)
{
cout << " Wating..." << flush;
lock_guard<mutex> lock(gMutex);
while(gCount > 0)
{
cout << "." << flush;
gCond.wait(gMutex);
}
cout << "." << endl;
}
// Thread function: Yield
void ThreadYield(void * aArg)
{
// Yield...
this_thread::yield();
}
// Thread function: Detach
void ThreadDetach(void * aArg)
{
// We don't do anything much, just sleep a little...
this_thread::sleep_for(chrono::milliseconds(100));
}
// This is the main program (i.e. the main thread)
int main()
{
// Test 1: Show number of CPU cores in the system
cout << "PART I: Info" << endl;
cout << " Number of processor cores: " << thread::hardware_concurrency() << endl;
// Test 2: thread IDs
cout << endl << "PART II: Thread IDs" << endl;
{
// Show the main thread ID
cout << " Main thread id is " << this_thread::get_id() << "." << endl;
// Start a bunch of child threads - only run a single thread at a time
thread t1(ThreadIDs, 0);
t1.join();
thread t2(ThreadIDs, 0);
t2.join();
thread t3(ThreadIDs, 0);
t3.join();
thread t4(ThreadIDs, 0);
t4.join();
}
// Test 3: thread local storage
cout << endl << "PART III: Thread local storage" << endl;
#ifndef NO_TLS
{
// Clear the TLS variable (it should keep this value after all threads are
// finished).
gLocalVar = 1;
cout << " Main gLocalVar is " << gLocalVar << "." << endl;
// Start a child thread that modifies gLocalVar
thread t1(ThreadTLS, 0);
t1.join();
// Check if the TLS variable has changed
if(gLocalVar == 1)
cout << " Main gLocalID was not changed by the child thread - OK!" << endl;
else
cout << " Main gLocalID was changed by the child thread - FAIL!" << endl;
}
#else
cout << " TLS is not supported on this platform..." << endl;
#endif
// Test 4: mutex locking
cout << endl << "PART IV: Mutex locking (100 threads x 10000 iterations)" << endl;
{
// Clear the global counter.
gCount = 0;
// Start a bunch of child threads
list<thread *> threadList;
for(int i = 0; i < 100; ++ i)
threadList.push_back(new thread(ThreadLock, 0));
// Wait for the threads to finish
list<thread *>::iterator it;
for(it = threadList.begin(); it != threadList.end(); ++ it)
{
thread * t = *it;
t->join();
delete t;
}
// Check the global count
cout << " gCount = " << gCount << endl;
}
// Test 5: fast_mutex locking
cout << endl << "PART V: Fast mutex locking (100 threads x 10000 iterations)" << endl;
{
// Clear the global counter.
gCount = 0;
// Start a bunch of child threads
list<thread *> threadList;
for(int i = 0; i < 100; ++ i)
threadList.push_back(new thread(ThreadLock2, 0));
// Wait for the threads to finish
list<thread *>::iterator it;
for(it = threadList.begin(); it != threadList.end(); ++ it)
{
thread * t = *it;
t->join();
delete t;
}
// Check the global count
cout << " gCount = " << gCount << endl;
}
// Test 6: condition variable
cout << endl << "PART VI: Condition variable (40 + 1 threads)" << endl;
{
// Set the global counter to the number of threads to run.
gCount = 40;
// Start the waiting thread (it will wait for gCount to reach zero).
thread t1(ThreadCondition2, 0);
// Start a bunch of child threads (these will decrease gCount by 1 when they
// finish)
list<thread *> threadList;
for(int i = 0; i < 40; ++ i)
threadList.push_back(new thread(ThreadCondition1, 0));
// Wait for the waiting thread to finish
t1.join();
// Wait for the other threads to finish
list<thread *>::iterator it;
for(it = threadList.begin(); it != threadList.end(); ++ it)
{
thread * t = *it;
t->join();
delete t;
}
}
// Test 7: yield
cout << endl << "PART VII: Yield (40 + 1 threads)" << endl;
{
// Start a bunch of child threads
list<thread *> threadList;
for(int i = 0; i < 40; ++ i)
threadList.push_back(new thread(ThreadYield, 0));
// Yield...
this_thread::yield();
// Wait for the threads to finish
list<thread *>::iterator it;
for(it = threadList.begin(); it != threadList.end(); ++ it)
{
thread * t = *it;
t->join();
delete t;
}
}
// Test 8: sleep
cout << endl << "PART VIII: Sleep (10 x 100 ms)" << endl;
{
// Sleep...
cout << " Sleeping" << flush;
for(int i = 0; i < 10; ++ i)
{
this_thread::sleep_for(chrono::milliseconds(100));
cout << "." << flush;
}
cout << endl;
}
// Test 9: detach
cout << endl << "PART IX: Detach" << endl;
{
thread t(ThreadDetach, 0);
t.detach();
cout << " Detached from thread." << endl;
}
}
So I tried to make my own code, but not only does the main thread not see the variable increment, but when I added sleep to the worker thread it no longer tries to print the variable on the main thread. Because of these two problems the worker thread never quits either.
#include <iostream>
#include <list>
#include "tinythread.h"
#include "fast_mutex.h"
using namespace std;
using namespace tthread;
fast_mutex workerThreadMutex;
bool killThread = false;
int number = 0;
void workerThread(void * aArg)
{
bool running = true;
int number = 0;
while(running)
{
lock_guard<fast_mutex> lock(workerThreadMutex);
number++;
cout << "secondThread::" << number << endl;
this_thread::sleep_for(chrono::milliseconds(1000));
if(killThread)
running =true;
}
}
int main()
{
thread* wThread = new thread(workerThread, 0);
bool running = true;
while(running)
{
this_thread::sleep_for(chrono::milliseconds(100));
if(workerThreadMutex.try_lock())
{
cout << "mainThread::" << number << endl;
if(number == 100)
{
killThread = true;
running = false;
}
workerThreadMutex.unlock();
}
}
wThread->join();
delete wThread;
return 0;
}
Can you help?
edit: made a change to my code
edit: fixed local variable issue, it works now, except for the kill thread boolean is not being detected so the secondary thread (worker thread) is not exiting.
edit: fixed issue with local variable
edit: fixed issue with sleep
edit: fixed issue killThread
edit: all problems fixed
#include <iostream>
#include <list>
#include "tinythread.h"
#include "fast_mutex.h"
using namespace std;
using namespace tthread;
fast_mutex workerThreadMutex;
bool killThread = false;
int number = 0;
bool running = true;
void workerThread(void * aArg)
{
while(running)
{
{
lock_guard<fast_mutex> lock(workerThreadMutex);
number++;
if(killThread)
running =false;
}
this_thread::sleep_for(chrono::milliseconds(50));
}
}
int main()
{
thread* wThread = new thread(workerThread, 0);
while(running)
{
this_thread::sleep_for(chrono::milliseconds(100));
if(workerThreadMutex.try_lock())
{
cout << "mainThread::" << number << endl;
if(number > 100)
{
killThread = true;
//running = false;
}
workerThreadMutex.unlock();
}
}
wThread->join();
delete wThread;
return 0;
}
edit: further modification to show portable c++11 friendly inter thread communication
#include <iostream>
#include <sstream>
#include "tinythread.h"
#include "fast_mutex.h"
using namespace std;
using namespace tthread;
fast_mutex workerThreadMutex;
bool killThread = false;
int number = 0;
bool running = true;
string message = "";
void workerThread(void * aArg)
{
while(running)
{
{
lock_guard<fast_mutex> lock(workerThreadMutex);
if(message=="")
{
number++;
ostringstream Convert;
Convert << number;
message = Convert.str();
}
if(killThread)
running =false;
}
this_thread::sleep_for(chrono::milliseconds(1));
}
}
int main()
{
thread* wThread = new thread(workerThread, 0);
bool stopMainThreadLoop = false;
while(!stopMainThreadLoop)
{
this_thread::sleep_for(chrono::milliseconds(10));
if(workerThreadMutex.try_lock())
{
//cout << "mainThread::" << number << endl;
cout << "mainThread::" << message << endl;
//if(number > 100)
if(message == "100")
{
killThread = true;
stopMainThreadLoop = true;
}
message = "";
workerThreadMutex.unlock();
}
}
wThread->join();
delete wThread;
return 0;
}
Look at this part of your code
int number = 0; // Global variable, i.e. will be used by main
void workerThread(void * aArg)
{
bool running = true;
int number = 0; // Local variable, i.e. will be used by in the function
So mainis using one variable and the function (aka the thread) is using another. Consequently main can't see any increments.
Just remove the local variable.
For the sleep part
I think the problem is that you do the sleep while holding the mutex.
Try this:
void workerThread(void * aArg)
{
bool running = true;
//---------------------- int number = 0;
while(running)
{
{
lock_guard<fast_mutex> lock(workerThreadMutex);
number++;
//cout << "secondThread::" << number << endl;
if(killThread)
running =true;
}
this_thread::sleep_for(chrono::milliseconds(1000));
}
}
For the kill:
Try this
if(number >= 100) // Changed
{
killThread = true;
running = false;
}
Inside the function
if(killThread)
running =true; // Should be false
What's meaning of field uc_stack in struct ucontext_t?Who use it? The coroutine or the coroutine's signal handler? How can I test it? For example
#include <iostream>
#include <ucontext.h>
#include <queue>
#include <signal.h>
using namespace std;
void sigHandler(int signo)
{
printf("sigHandler:%x\n", &signo);
exit(-1);
}
queue<int> qProduct;
void consumer(ucontext_t* pConsumer, ucontext_t* pProducer)
{
char a[SIGSTKSZ] = {0};
while(1)
{
if(qProduct.size() > 0)
{
cout << __FUNCTION__ << "|" << qProduct.front() << endl;
qProduct.pop();
}
else
{
cout << pConsumer << "|" << pProducer << endl;
swapcontext(pConsumer, pProducer);
}
}
}
void producer(ucontext_t* pConsumer, ucontext_t* pProducer, bool* pFinished)
{
for(int i=0; i<10; i++)
{
if(qProduct.size() < 5)
{
qProduct.push(i);
cout << __FUNCTION__ << "|" << i << endl;
}
else
{
cout << pConsumer << "|P|" << pProducer << endl;
swapcontext(pProducer, pConsumer);
}
}
cout << pConsumer << "|P|" << pProducer << endl;
swapcontext(pProducer, pConsumer);
*pFinished = true;
}
int main(int argc, char* argv[])
{
ucontext_t Main, Consumer, Producer;
/* The stack for the iterator function. */
char consumer_stack[SIGSTKSZ];
char producer_stack[SIGSTKSZ];
cout << "SIGSTKSZ:" << SIGSTKSZ << endl;
/* Flag indicating that the iterator has completed. */
volatile bool bFinished = false;
getcontext(&Consumer);
Consumer.uc_link = &Main;
Consumer.uc_stack.ss_sp = consumer_stack;
Consumer.uc_stack.ss_size = sizeof(consumer_stack);
makecontext(&Consumer, (void (*)(void))consumer, 2, &Consumer, &Producer);
getcontext(&Producer);
Producer.uc_link = &Main;
Producer.uc_stack.ss_sp = producer_stack;
Producer.uc_stack.ss_size = sizeof(producer_stack);
makecontext(&Producer, (void (*)(void))producer, 3, &Consumer, &Producer, &bFinished);
if(!bFinished)
{
swapcontext(&Main, &Producer);
}
return 0;
}
Who use the stack "consumer_stack", "consumer" or "sigHandler"?How to prove it?
I can't figure out where is the problem with this simple code, I think that here is the trouble with output to Console maybe deadlock or something, can somebody, please help.
#include <iostream>
#include <string>
#include <sstream>
#include <boost/thread.hpp>
using namespace std;
struct IntegrateTask
{
int id;
double from, to, step, result;
IntegrateTask(int id, double from, double to, double step)
{
this -> id;
this -> from = from;
this -> to = to;
this -> step = step;
}
~IntegrateTask()
{}
};
vector<IntegrateTask> * tasks = new vector<IntegrateTask>();
boost::mutex mutlist;
boost::mutex iomutex;
boost::condition_variable condtask;
bool isInterrupted = false;
double foo(double x)
{
return x * x;
}
void integrate(IntegrateTask * task)
{
double result = 0;
double step = task -> step;
for(double i = task -> from ; i != task -> to; i =+ step)
{
result += foo(i) * step;
}
task -> result = result;
}
void integrateThread()
{
boost::thread::id id = boost::this_thread::get_id();
try
{
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Thread #" << id << " is working!" << endl;
}
while(!isInterrupted)
{
IntegrateTask * currtask = NULL;
{
boost::mutex::scoped_lock lock(mutlist);
while(!isInterrupted && tasks -> empty())
{
condtask.wait(lock);
}
if (!tasks -> empty())
{
currtask = &tasks->back();
tasks->pop_back();
}
}
if (currtask != NULL)
{
integrate(currtask);
boost::mutex::scoped_lock iolock(iomutex);
cout << "Task #" << (currtask->id) << "; result = " << (currtask->result) << endl;
}
}
boost::mutex::scoped_lock iolock(iomutex);
cout << "Thread # " << id << " stoped working normal!" << endl;
}
catch(boost::thread_interrupted)
{
boost::mutex::scoped_lock ioLock(iomutex);
cout << "Thread # " << id << " stoped working by interruption!" << endl;
}
catch(exception & e)
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Error: " << e.what() << endl;
}
}
int main()
{
cout << "Function for integration: f(x)=x*x" << endl;
cout << "For stopping program press EXIT" << endl;
int thcount = 6;// or boost::thread::hardware_concurrency()
boost::thread_group thgroup;
for (int i = 1; i <= thcount; i++){
thgroup.create_thread(&integrateThread);
}
int id = 0;
while (true)
{
string line;
{
boost::mutex::scoped_lock iolock(iomutex);
cout << "Task #" << ++id << "; left bound, right bound and step: ";
getline(cin, line);
}
if (line.find("e") != string::npos)
{
isInterrupted = true;
condtask.notify_all();
thgroup.interrupt_all();
thgroup.join_all();
return 0;
}
double from, to, step;
istringstream input(line);
input >> from >> to >> step;
IntegrateTask * task = new IntegrateTask(id, from, to, step);
{
boost::mutex::scoped_lock lock(mutlist);
tasks->push_back(*task);
}
condtask.notify_one();
}
}
I haven't tried to follow the logic of what you're aiming to achieve here, but there are 2 issues (at least):
You're not using id in IntegrateTask's constructor. You should generally favour initialisation lists over assignments in constructor bodies, and using class member variable names in function signatures is a recipe for disaster too, so I'd change your constructor to:
IntegrateTask(int id_init, double from_init, double to_init, double step_init)
: from(from_init), to(to_init), step(step_init), id(id_init) {}
The probable cause of the hanging is your use of != in the for loop in integrate. If you change that to < your program shouldn't hang, but I'm not sure if this breaks your program's logic.