I'm playing with C++(11) STL and got the following problem.
The basic idea for this code is:
I have a "trigger" function, an "add" function and a flag(false by default). If the flag is false the "add" function's going to push the threadID to a queue, otherwise it's going to insert the threadID to the set. When the trigger function is called, it set the flag to "true" and move threadIDs from the queue to the set.
I initialized 100 threads and use one of the thread to run the trigger function(in the code it's thread NO.30). Ideally the result should have 0 elements in the queue and 99 elements in the set.
However, sometimes the result is correct, sometimes I missed some numbers in the set, and sometimes I got the EXC_BAD_ACCESS error.
Could anyone help? Thank you.
#include <iostream>
#include <thread>
#include <vector>
#include <unordered_set>
#include <queue>
#include <mutex>
#include <atomic>
using namespace std;
bool flag = false;
queue<int> q;
unordered_set<int> s;
mutex mu;
void trigger()
{
mu.lock();
flag = true;
mu.unlock();
while( !q.empty() ){
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
mu.lock();
if( !flag )
q.push(id);
else {
if ( s.find(id) == s.end() ){
s.insert(id);
}
}
mu.unlock();
}
void missing()
{
cout << "Missing Numbers: ";
for (int i = 1; i <= 100; i++) {
if( s.find(i) == s.end() )
cout << i << " ";
}
cout << endl;
}
int main()
{
vector<thread> threads;
for (int i = 0; i < 100; i++){
if ( i == 29 ) threads.push_back(thread(trigger));
else threads.push_back(thread(add, i+1));
}
for (int i = 0; i < 100; i++){
threads[i].join();
}
cout << "Q size: " << q.size() << endl;
cout << "S size: " << s.size() << endl;
missing();
}
You have 1 thread executing the trigger function and many threads executing the add function. Furthermore, you take care to guard some of the shared state but not all of it. See my comments/questions in the below code snippets.
void trigger()
{
// Only the 'flag' is protected from concurrent acceess
mu.lock();
flag = true;
mu.unlock();
// Why isn't 'q' or 's' protected by a lock?
while( !q.empty() ){
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
// In this function both 'q' and 's' are protected from concurrent access
mu.lock();
if( !flag )
q.push(id);
else {
if ( s.find(id) == s.end() ){
s.insert(id);
}
}
mu.unlock();
}
Possible Solution
In general, you should protect any state being accessed concurrently. I'd also recommend using a lock type (e.g., lock_guard) instead of locking and unlocking the mutex directly (research RAII for why this is encouraged).
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <unordered_set>
#include <vector>
using namespace std;
bool flag = false;
queue<int> q;
unordered_set<int> s;
mutex mu;
void trigger()
{
lock_guard<mutex> lock(mu);
flag = true;
while (!q.empty())
{
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
lock_guard<mutex> lock(mu);
if (!flag)
{
q.push(id);
}
else
{
if (s.find(id) == s.end())
{
s.insert(id);
}
}
}
void missing()
{
cout << "Missing Numbers: ";
for (int i = 1; i <= 100; ++i)
{
if (s.find(i) == s.end())
{
cout << i << " ";
}
}
cout << endl;
}
int main()
{
vector<thread> threads;
for (int i = 0; i < 100; ++i)
{
if (i == 29)
{
threads.push_back(thread(trigger));
}
else
{
threads.push_back(thread(add, i + 1));
}
}
for (int i = 0; i < 100; ++i)
{
threads[i].join();
}
cout << "Q size: " << q.size() << endl;
cout << "S size: " << s.size() << endl;
missing();
return 0;
}
Related
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 have 4-threads in my program. I want to execute all of them once and once all of them are executed then only I want to enter the next iteration of execution.
I got a code on stack overflow that implements the boost::barrier function in C++. But it does not seem to work for me. For one iteration it works fine. But for the next iteration, the program execution just hangs.
//Here is my top code:
#include <iostream>
#include <stdio.h>
#include <thread>
#include "abc_func.hpp"
#include <vector>
using namespace std;
int main() {
abc obj1;
obj1.num_threads(4);
std::thread t1([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_write(1));
};
});
std::thread t2([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_read(2));
};
});
std::thread t3([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_write(3));
};
});
std::thread t4([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_read(4));
};
});
t1.join();
t2.join();
t3.join();
t4.join();
// cout << "done: " << obj1.done << endl;
// cout << "done: " << obj2.done << endl;
// cout << "wr_count: " << obj1.wr_count << endl;
return 0;
}
// Here is the abc_func.hpp
#include <iostream>
#include <stdio.h>
#include <thread>
#include <barrier.hpp>
using namespace std;
class abc {
size_t n_threads;
public:
abc() : n_threads(0) {};
void num_threads (size_t l) {
n_threads = l;
}
Barrier task_bar{n_threads};
bool abc_write (auto id) {
thread_local int wr_count = 0;
if (wr_count == 1) {
std::cout << "write thread waiting" << id << endl;
task_bar.Wait();
wr_count = 0;
};
std::cout << "write thread running " << id << endl;
++wr_count;
return true;
}
bool abc_read (auto id) {
thread_local int rd_count=0;
if (rd_count == 1) {
std::cout << "read thread waiting" << id << endl;
task_bar.Wait();
rd_count = 0;
};
std::cout << "read thread running " << id << endl;
++rd_count;
return true;
}
};
// and the barrier class code which I got on stack overflow
#include <thread>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <stdio.h>
class Barrier {
public:
explicit Barrier(std::size_t iCount) :
mThreshold(iCount),
mCount(iCount),
mGeneration(0) {
}
void Wait() {
std::unique_lock<std::mutex> lLock{mMutex};
auto lGen = mGeneration;
if (!--mCount) {
mGeneration++;
mCount = mThreshold;
mCond.notify_all();
} else {
mCond.wait(lLock, [this, lGen] { return lGen != mGeneration; });
}
}
private:
std::mutex mMutex;
std::condition_variable mCond;
std::size_t mThreshold;
std::size_t mCount;
std::size_t mGeneration;
};
The problem with this code is the member
Barrier task_bar{n_threads};
It is initialized once at the beginning while n_threads is 0. Later, when you call
obj1.num_threads(4);
the barrier object is not updated.
When you update the barrier as well, it works as expected
class Barrier {
public:
// ...
void num_threads(size_t n) {
mThreshold = n;
mCount = n;
}
// ...
};
and in abc::num_threads()
void num_threads (size_t l) {
n_threads = l;
task_bar.num_threads(l);
}
I'm writing a chess engine , and this is an example of how I want to implement the UCI protocol:
//search.h
#pragma once
#include<atomic>
static std::atomic_bool stop=false;
namespace Search
{
int Alphabeta()
{
int r = 10;
int Rounds = 0;
while ((++Rounds<20)&&!stop)
{
int sum = 0;
for (size_t i = 0; i < 100000000; i++)
{
sum += i;
}
sync_cout << sum<< sync_endl;
}
sync_cout << "Stopping" << sync_endl;
return r;
}
}
//UCI.h
#pragma once
#include<iostream>
#include<string>
#include <sstream>
#include<thread>
#include<mutex>
#include<condition_variable>
enum SyncCout { IO_LOCK, IO_UNLOCK };
//taken from StockFish
std::ostream& operator<<(std::ostream& os, SyncCout sc) {
static std::mutex m;
if (sc == IO_LOCK) m.lock();
if (sc == IO_UNLOCK) m.unlock();
return os;
}
#define sync_cout std::cout << IO_LOCK
#define sync_endl std::endl << IO_UNLOCK
#include"search.h"
class Thread
{
public:
Thread()
{
nativeThread = std::thread(&Thread::MainLoop, this);
sync_cout << "#Constructor" << sync_endl;
}
void MainLoop()
{
while (!exit)
{
while (pause)
{
sync_cout << "#Waiting" << sync_endl;
std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk);
lk.unlock();
}
sync_cout << "#UCILoop" << sync_endl;
std::string token, cmd;
while (!pause && !exit && std::getline(std::cin, cmd))
{
sync_cout << "#Processing" << sync_endl;
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "stop")
{
stop = true;
PauseThread();
}
else if (token == "isready") std::cout << "readyok" << std::endl;
else if (token == "pause") PauseThread();
}
}
}
void PauseThread()
{
//pause
std::lock_guard<std::mutex> lk(mutex);
pause = true;
}
void ResumeThread()
{
std::lock_guard<std::mutex> lk(mutex);
pause = false;
cv.notify_one();
}
~Thread()
{
sync_cout << "#Destructor" << sync_endl;
mutex.lock();
pause = false;
exit = true;
cv.notify_one();
mutex.unlock();
nativeThread.join();
}
private:
std::thread nativeThread;
std::mutex mutex;
std::condition_variable cv;
bool pause = true, exit = false;
};
namespace UCI
{
void Loop()
{
Thread th;
std::cout << "#PrimaryLoop : "<<std::endl;
std::string token, cmd;
while (std::getline(std::cin, cmd))
{
std::cout << "Processing : ";
std::istringstream is(cmd);
is >> std::skipws >> token;
if (token == "go")
{
std::cout << "go ok" << std::endl;
stop = false;
th.ResumeThread();
Search::Alphabeta();
th.PauseThread();
}
else if (token == "isready") std::cout << "readyok" << std::endl;
else if (token == "quiet")
{
std::cout << "quieting" << std::endl;
break;
}
}
}
}
and main :
#include"UCI.h"
int main()
{
UCI::Loop();
}
Everything works ok with the only exception being the case when the search finishes normally without receiving the UCI command "stop" , so the search will return while the secondary UCI thread is waiting for input #"std::getline" , I intended to write to the stdin stream "pause" as can be seen from the code before knowing that this is at the very best non portable & wrong , what are my options or is there another way to pause a thread regardless of what it's currently executing ?
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
I am using C++11 on Mac OS Xcode 4.3.2
std::async uses same thread and my code does not achieve parallelism. In sample code below I want to create 10 new threads. In each thread I want to calculate square root of input variable and set the result in promise. in main function I want to display the results calculated from threads. I am calling std::async with policy launch::async, So I expect it to create a new thread(10 times).
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
void foo(int i, promise<double> &&prms)
{
this_thread::sleep_for(chrono::seconds(2));
prms.set_value(sqrt(i));
{
lock_guard<mutex> lg(iomutex);
cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id();
}
}
int main()
{
{
lock_guard<mutex> lg(iomutex);
cout << endl << "main thread id=>"<< this_thread::get_id();
}
vector<future<double>> futureVec;
vector<promise<double>> prmsVec;
for (int i = 0; i < 10; ++i) {
promise<double> prms;
future<double> ftr = prms.get_future();
futureVec.push_back(move(ftr));
prmsVec.push_back(move(prms));
async(launch::async, foo, i, move(prmsVec[i]));
}
for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) {
cout << endl << iter->get();
}
cout << endl << "done";
return 0;
}
However if I use std::thread, then I can achieve parallelism.
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
void foo(int i, promise<double> &&prms)
{
this_thread::sleep_for(chrono::seconds(2));
prms.set_value(sqrt(i));
{
lock_guard<mutex> lg(iomutex);
cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id();
}
}
int main()
{
{
lock_guard<mutex> lg(iomutex);
cout << endl << "main thread id=>"<< this_thread::get_id();
}
vector<future<double>> futureVec;
vector<promise<double>> prmsVec;
vector<thread> thrdVec;
for (int i = 0; i < 10; ++i) {
promise<double> prms;
future<double> ftr = prms.get_future();
futureVec.push_back(move(ftr));
prmsVec.push_back(move(prms));
thread th(foo, i, move(prmsVec[i]));
thrdVec.push_back(move(th));
}
for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) {
cout << endl << iter->get();
}
for (int i = 0; i < 10; ++i) {
thrdVec[i].join();
}
cout << endl << "done";
return 0;
}
async(launch::async, foo, i, move(prmsVec[i]));
This line returns a future but because you do not assign it to anything the future's destructor runs at the end of the statement, which blocks and waits for the result by calling std::future::wait()
Why are you manually calling std::async with a promise, when it returns a future anyway? The point of async is that you don't need to manually use a promise, that's done internally for you.
Rewrite your foo() to return double then call it with async
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
double foo(int i)
{
this_thread::sleep_for(chrono::seconds(2));
lock_guard<mutex> lg(iomutex);
cout << "\nthread index=> " << i << ", id=> "<< this_thread::get_id();
return sqrt(i);
}
int main()
{
cout << "\nmain thread id=>" << this_thread::get_id();
vector<future<double>> futureVec;
for (int i = 0; i < 10; ++i)
futureVec.push_back(async(launch::async, foo, i));
for (auto& fut : futureVec)
{
auto x = fut.get();
lock_guard<mutex> lg(iomutex);
cout << endl << x;
}
cout << "\ndone\n";
}