pthread and conditional variables - concurrency

I am following the tutorial on pthread from here.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_cond = PTHREAD_COND_INITIALIZER;
void *functionCount1();
void *functionCount2();
int count = 0;
#define COUNT_DONE 10
#define COUNT_HALT1 3
#define COUNT_HALT2 6
main()
{
pthread_t thread1, thread2;
pthread_create( &thread1, NULL, &functionCount1, NULL);
pthread_create( &thread2, NULL, &functionCount2, NULL);
pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
exit(0);
}
void *functionCount1()
{
for(;;)
{
pthread_mutex_lock( &condition_mutex );
while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
{
pthread_cond_wait( &condition_cond, &condition_mutex );
}
pthread_mutex_unlock( &condition_mutex );
pthread_mutex_lock( &count_mutex );
count++;
printf("Counter value functionCount1: %d\n",count);
pthread_mutex_unlock( &count_mutex );
if(count >= COUNT_DONE) return(NULL);
}
}
void *functionCount2()
{
for(;;)
{
pthread_mutex_lock( &condition_mutex );
if( count < COUNT_HALT1 || count > COUNT_HALT2 )
{
pthread_cond_signal( &condition_cond );
}
pthread_mutex_unlock( &condition_mutex );
pthread_mutex_lock( &count_mutex );
count++;
printf("Counter value functionCount2: %d\n",count);
pthread_mutex_unlock( &count_mutex );
if(count >= COUNT_DONE) return(NULL);
}
}
And the author adds that functioncount1() is halted for values between the values COUNT_HALT1 and COUNT_HALT2.
A sample output is as follows:
Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount2: 5
Counter value functionCount2: 6
Counter value functionCount2: 7
Counter value functionCount1: 8
Counter value functionCount1: 9
Counter value functionCount1: 10
Counter value functionCount2: 11
From my observation of the code, shouldn't 3 be counted by functionCount2? In the while loop in functionCount1, it calls wait() on any value including 3, which leads me to think that 3 should be counted by functionCount2, instead of functionCount1.
Why isn't it so?

One thread may read count with only the condition_mutex held (where count is tested against COUNT_HALT1 and COUNT_HALT) or with no mutex held at all (where count is tested against COUNT_DONE) while the other thread can modify count with only the count_mutex held. This unsynchronised access results in undefined behaviour, as #EOF noted in comments to the question, so the code is simply incorrect.
That said, even if we ran only functionCount1() without the other thread (so that the unsynchronised access does not occur), we would still expect to see this output:
Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
That's because the counter value is printed after the increment, so in the last iteration it sees an initial counter value of 2, does not wait, increments the counter, then prints the new counter value of 3.
Note that in your original code, even ignoring the unsynchronised access, there is still a possibility for functionCount1 to perform the increment from 3 to 4. This is because in between functionCount1 seeing a count value of 2 and deciding not to wait, and actually locking the count_mutex, the value could be incremented by the other thread.
To remove both the unsynchronised access to count and fix the race referred to the in previous paragraph, you simply remove condition_mutex entirely and use count_mutex instead, keeping it locked between the pthread_cond_wait() return and the actual increment of count. This is the general pattern: the mutex you have locked when you call pthread_cond_wait() should be the mutex protecting the shared state that you are waiting for with your condition variable (here, that shared state is just the count variable):
void *functionCount1()
{
for(;;)
{
pthread_mutex_lock( &count_mutex );
while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
{
pthread_cond_wait( &condition_cond, &count_mutex );
}
count++;
printf("Counter value functionCount1: %d\n",count);
if (count >= COUNT_DONE)
{
pthread_mutex_unlock( &count_mutex );
return(NULL);
}
pthread_mutex_unlock( &count_mutex );
}
}
void *functionCount2()
{
for(;;)
{
pthread_mutex_lock( &count_mutex );
if( count < COUNT_HALT1 || count > COUNT_HALT2 )
{
pthread_cond_signal( &condition_cond );
}
count++;
printf("Counter value functionCount2: %d\n",count);
if (count >= COUNT_DONE)
{
pthread_mutex_unlock( &count_mutex );
return(NULL);
}
pthread_mutex_unlock( &count_mutex );
}
}
This is not optimal, however: the mutex is kept locked for longer than necessary. If you don't care about arbitrary output interleaving between the threads, then you don't need to have count_mutex locked while you call printf(), as long as you take a local copy of the new count value to pass to printf(). You can also use that local copy in the exit test as well.
Furthermore, the signalling condition only needs to be tested after functionCount2() has changed count. pthread_mutex_signal() doesn't have to be called with the mutex held, so we can put that after the printf() as well, using the local copy of the count:
void *functionCount1()
{
for(;;)
{
int my_count;
pthread_mutex_lock( &count_mutex );
while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
{
pthread_cond_wait( &condition_cond, &count_mutex );
}
count++;
my_count = count;
pthread_mutex_unlock( &count_mutex );
printf("Counter value functionCount1: %d\n", my_count);
if (my_count >= COUNT_DONE)
return(NULL);
}
}
void *functionCount2()
{
for(;;)
{
int my_count;
pthread_mutex_lock( &count_mutex );
count++;
my_count = count;
pthread_mutex_unlock( &count_mutex );
printf("Counter value functionCount2: %d\n", my_count);
if ( my_count < COUNT_HALT1 || my_count > COUNT_HALT2 )
{
pthread_cond_signal( &condition_cond );
}
if (my_count >= COUNT_DONE)
return(NULL);
}
}
As noted above, you probably won't see the printf() output ordered in strict count order anymore, because we're no longer forcing the printf() to happen atomically with the increment.

Related

Can I change data with a std::shared_lock on a std::shared_mutex?

I have multiple buffers being shared with multiple reader/writer threads, and different writers change the data as different manners.
For example, Writer1 merely appends new data, while Writer2 extends the size of buffer(re-alloc memory and move data).
If I put a single mutex to sync all the accesses to the data, the performance maybe not better, because most reader just need to read a single buffer, and most writer just need to write a little piece of data to a single buffer.
If I prepare one mutex for each buffer, the locking/unlocking relationship between threads will be more complicated.
Now I want to confirm a thing:
If a writer change the data only with a shared_lock on the mutex, whether the others would see dirty data with a unique_lock/shared_lock on same mutex?
I coded an experimental program as following, and it looks like no error, but I still dare not use it in product.
atomic_bool g_abShouldRun = true;
sem_t g_semDoIt1;
sem_t g_semDone1;
sem_t g_semDoIt2;
sem_t g_semDone2;
shared_mutex g_mutex;
int g_iX = 3, g_iY = 9, g_iR1 = 1, g_iR2 = 3;
void writer() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt1 );
while( rand() % 8 != 0 )
;
{
shared_lock<shared_mutex> lk( g_mutex );
g_iX *= 2;
g_iY *= 2;
}
sem_post( &g_semDone1 );
};
};
void reader() {
std::srand( 8 );
while( g_abShouldRun ) {
sem_wait( &g_semDoIt2 );
while( rand() % 8 != 0 )
;
{
unique_lock<shared_mutex> lk( g_mutex );
g_iR1 = g_iX;
g_iR2 = g_iY;
}
sem_post( &g_semDone2 );
};
};
int main( int argc, char** argv ) {
int iLasting = 10, iError = 0;
if( argc > 1 )
iLasting = atoi( argv[1] );
steady_clock::time_point tpEnd = steady_clock::now() + seconds( iLasting );
if( sem_init( &g_semDoIt1, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ||
sem_init( &g_semDoIt2, 0, 0 ) || sem_init( &g_semDone2, 0, 0 ) ) {
cerr << "Failed to create semaphors." << endl;
return EXIT_FAILURE;
}
thread thd1( writer );
thread thd2( reader );
while( steady_clock::now() < tpEnd ) {
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
sem_wait( &g_semDone1 );
sem_wait( &g_semDone2 );
if( g_iR1 * 3 != g_iR2 )
++iError;
}
g_abShouldRun = false;
sem_post( &g_semDoIt1 );
sem_post( &g_semDoIt2 );
thd1.join();
thd2.join();
sem_destroy( &g_semDoIt1 );
sem_destroy( &g_semDoIt2 );
sem_destroy( &g_semDone1 );
sem_destroy( &g_semDone2 );
cout << "Error:" << iError << endl;
return EXIT_SUCCESS;
};
The following problems jump out at a quick look:
change the code to use unique_lock when writing;
change the code to use shared_lock when reading;
do not modify other common global variables when reading -- that will practically be writing, just in a different place;
how many { shared_mutexs, function using unique_lock, function using shared_lock } tuples you'll be using with multiple threads and multiple buffers, you'll need to figure out yourself -- but it'll be between 1 and the number of buffers.

Boost Shared_lock / Unique_lock, giving the writer priority?

I have a multithreaded application that i am writing using Boost Thread locking.
In this case, there is one writer, and multiple readers. As I have it now, the writer seems to wait for all the readers to complete before it can write again.
What i want, is to give the writer priority, so that if it wants to write again, it does so, no matter what. the readers work around it.
For example:
Now:
Writer;
reader1;
reader2;
reader3;
reader4;
What i would like, is:
Writer;
reader1;
reader2;
Writer(if ready);
reader3;
reader4;
Is this possible? My code is replicated below:
typedef boost::shared_mutex Lock;
typedef boost::unique_lock< Lock > WriteLock;
typedef boost::shared_lock< Lock > ReadLock;
Lock frameLock;
cv::Mat currentFrame;
bool frameOk;
void writer()
{
while (true)
{
cv::Mat frame;
cv::Mat src = cv::imread("C:\\grace_17.0001.jpg");
cv::resize(src, frame, cv::Size(src.cols / 4, src.rows / 4));
int64 t0 = cv::getTickCount();
WriteLock w_lock(frameLock);
frame.copyTo(currentFrame);
frameLock.unlock();
frameOk = true; // tells read we have at least one frame
int64 t1 = cv::getTickCount();
double secs = (t1 - t0) / cv::getTickFrequency();
std::cout << "wait time WRITE: " << secs * 1000 << std::endl;
}
}
void readerTwo(int wait)
{
while (true)
{
if (frameOk) // if first frame is written
{
static cv::Mat readframe;
int64 t0 = cv::getTickCount();
//gets frame
ReadLock r_lockz(frameLock);
currentFrame.copyTo(readframe);
r_lockz.unlock();
std::cout << "READ: " << std::to_string(wait)<< std::endl;
cv::imshow(std::to_string(wait), readframe);
cv::waitKey(1);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
}
void main()
{
const int readerthreadcount = 50;
std::vector<boost::thread*> readerthread;
boost::thread* wThread = new boost::thread(writer);
for (int i = 0; i<readerthreadcount; i++) {
ostringstream id; id << "reader" << i + 1;
readerthread.push_back(new boost::thread(readerTwo, (i)));
}
wThread->join(); delete wThread;
for (int i = 0; i<readerthreadcount; i++) {
readerthread[i]->join(); delete readerthread[i];
}
}
Thank you.
Writer starvation is a typical problem with reader/writer locks.
Reader/writer locks unfortunately have to be tuned per-algorithm and per-architecture. (At least until something smarter is developed.)
Is this possible?
Yes, it's possible. With condition variables. Have a count waitingWriters. When a writer comes in, it acquires the mutex, increments waitingWriters, then waits on condition readerCount == 0. When a reader thread ends, it acquires the mutex, decrements readerCount, and signals the writer condition if readerCount == 0. When a reader thread comes in, it acquires the mutex. If waitingWriters == 0, increment readerCount and release the mutex. Otherwise wait on condition waitingWriters == 0. When a writer thread finishes, it acquires the mutex. If waitingWriters == 0, it signals the reader condition. Otherwise, it signals the next writer.
Note that this algorithm I just gave you:
Now prioritizes writes over reads. It is the other extreme in that
reads can be starved instead of writes.
Only uses 1 mutex. (not a
reader mutex & writer mutex)
Wouldn't be suitable for quick reads i.e. reads whose read operation is shorter than one scheduling timeslice. For that you would want to use spinlocks (check out the Big Reader)
The tuning depends on many factors, the most important of which are the ratio of reader vs writer threads and how long the critical sections are.
Here is my higly efficient write-prioritized shared mutex. In optimal cases, it needs only one atomic exchange for locking and unlocking - in contrast to other implementations which need two atomic exchanges.
#pragma once
#include <cstdint>
#include <cassert>
#include <thread>
#include <new>
#include <atomic>
#include "semaphore.h"
static_assert(std::atomic<std::uint64_t>::is_always_lock_free, "std::uint64_t must be lock-free");
class alignas(std::hardware_constructive_interference_size) wprio_shared_mutex
{
public:
wprio_shared_mutex();
wprio_shared_mutex( wprio_shared_mutex const & ) = delete;
~wprio_shared_mutex();
void lock_shared();
void unlock_shared();
void shared_to_write();
void lock_writer();
void write_to_shared();
void unlock_writer();
bool we_are_writer();
private:
std::atomic<std::uint64_t> m_atomic; // bit 0 - 20: readers
// bit 21 - 41: waiting readers
// bit 42 - 62: waiting writers
// bit 61: writer-flag
std::thread::id m_writerId;
std::uint32_t m_writerRecursionCount;
semaphore m_releaseReadersSem,
m_releaseWriterSem;
static unsigned const WAITING_READERS_BASE = 21,
WAITING_WRITERS_BASE = 42,
WRITER_FLAG_BASE = 63;
static std::uint64_t const MASK21 = 0x1FFFFFu;
static std::uint64_t const READERS_MASK = MASK21,
WAITING_READERS_MASK = MASK21 << WAITING_READERS_BASE,
WAITING_WRITERS_MASK = MASK21 << WAITING_WRITERS_BASE,
WRITER_FLAG_MASK = (std::uint64_t)1 << WRITER_FLAG_BASE;
static std::uint64_t const READER_VALUE = (std::uint64_t)1,
WAITING_READERS_VALUE = (std::uint64_t)1 << WAITING_READERS_BASE,
WAITING_WRITERS_VALUE = (std::uint64_t)1 << WAITING_WRITERS_BASE;
static bool check( std::uint64_t flags );
};
inline
bool wprio_shared_mutex::check( std::uint64_t flags )
{
unsigned readers = (unsigned)(flags & MASK21),
waitingReaders = (unsigned)((flags >> WAITING_READERS_BASE) & MASK21),
waitingWriters = (unsigned)((flags >> WAITING_WRITERS_BASE) & MASK21),
writerFlag = (unsigned)((flags >> WRITER_FLAG_BASE) & 1);
if( readers && (waitingReaders || writerFlag) )
return false;
if( waitingReaders && (readers || !writerFlag) )
return false;
if( waitingWriters && !(writerFlag || readers) )
return false;
if( writerFlag && readers )
return false;
return true;
}
wprio_shared_mutex::wprio_shared_mutex()
{
m_atomic.store( 0, std::memory_order_relaxed );
}
wprio_shared_mutex::~wprio_shared_mutex()
{
assert(m_atomic == 0);
}
void wprio_shared_mutex::lock_shared()
{
using namespace std;
for( uint64_t cmp = m_atomic.load( std::memory_order_relaxed ); ; )
{
assert(check( cmp ));
if( (cmp & WRITER_FLAG_MASK) == 0 )
[[likely]]
{
if( m_atomic.compare_exchange_weak( cmp, cmp + READER_VALUE, memory_order_acquire, memory_order_relaxed ) )
[[likely]]
return;
}
else
if( m_atomic.compare_exchange_weak( cmp, cmp + WAITING_READERS_VALUE, memory_order_relaxed, memory_order_relaxed ) )
[[likely]]
{
m_releaseReadersSem.forced_wait();
return;
}
}
}
void wprio_shared_mutex::unlock_shared()
{
using namespace std;
for( uint64_t cmp = m_atomic.load( std::memory_order_relaxed ); ; )
{
assert(check( cmp ));
assert((cmp & READERS_MASK) >= READER_VALUE);
if( (cmp & READERS_MASK) != READER_VALUE || (cmp & WAITING_WRITERS_MASK) == 0 )
[[likely]]
{
if( m_atomic.compare_exchange_weak( cmp, cmp - READER_VALUE, memory_order_relaxed, memory_order_relaxed ) )
[[likely]]
return;
}
else
{
assert(!(cmp & WRITER_FLAG_MASK));
if( m_atomic.compare_exchange_weak( cmp, (cmp - READER_VALUE - WAITING_WRITERS_VALUE) | WRITER_FLAG_MASK, memory_order_relaxed, memory_order_relaxed ) )
[[likely]]
{
m_releaseWriterSem.forced_release( 1 );
return;
}
}
}
}
void wprio_shared_mutex::shared_to_write()
{
using namespace std;
for( uint64_t cmp = m_atomic.load( std::memory_order_relaxed ); ; )
{
assert(check( cmp ));
assert((cmp & READERS_MASK) >= READER_VALUE);
if( (cmp & READERS_MASK) == READER_VALUE )
[[likely]]
{
assert(!(cmp & WRITER_FLAG_MASK));
if( m_atomic.compare_exchange_weak( cmp, (cmp - READER_VALUE) | WRITER_FLAG_MASK, memory_order_acquire, memory_order_relaxed ) )
[[likely]]
{
m_writerId = this_thread::get_id();
m_writerRecursionCount = 0;
return;
}
}
else
{
assert((cmp & READERS_MASK) > READER_VALUE);
if( m_atomic.compare_exchange_weak( cmp, cmp - READER_VALUE + WAITING_WRITERS_VALUE, memory_order_relaxed, memory_order_relaxed ) )
[[likely]]
{
m_releaseWriterSem.forced_wait();
m_writerId = this_thread::get_id();
m_writerRecursionCount = 0;
return;
}
}
}
}
void wprio_shared_mutex::lock_writer()
{
using namespace std;
uint64_t cmp = m_atomic.load( std::memory_order_acquire );
if( (cmp & WRITER_FLAG_MASK) && m_writerId == this_thread::get_id() )
{
++m_writerRecursionCount;
return;
}
for( ; ; )
{
assert(check( cmp ));
if( (cmp & (WRITER_FLAG_MASK | READERS_MASK)) == 0 )
[[likely]
{
if( m_atomic.compare_exchange_weak( cmp, cmp | WRITER_FLAG_MASK, memory_order_acquire, memory_order_relaxed ) )
[[likely]
{
m_writerId = this_thread::get_id();
m_writerRecursionCount = 0;
return;
}
}
else
if( m_atomic.compare_exchange_weak( cmp, cmp + WAITING_WRITERS_VALUE, memory_order_relaxed, memory_order_relaxed ) )
[[likely]]
{
m_releaseWriterSem.forced_wait();
m_writerId = this_thread::get_id();
m_writerRecursionCount = 0;
return;
}
}
}
void wprio_shared_mutex::unlock_writer()
{
using namespace std;
uint64_t cmp = m_atomic.load( std::memory_order_relaxed );
if( (cmp & WRITER_FLAG_MASK) && m_writerRecursionCount && m_writerId == this_thread::get_id() )
{
--m_writerRecursionCount;
return;
}
m_writerId = thread::id();
for( ; ; )
{
assert(cmp & WRITER_FLAG_MASK && !(cmp & READERS_MASK));
assert(check( cmp ));
if( (cmp & WAITING_WRITERS_MASK) != 0 )
[[unlikely]]
if( m_atomic.compare_exchange_weak( cmp, cmp - WAITING_WRITERS_VALUE, memory_order_release, memory_order_relaxed ) )
[[likely]]
{
m_releaseWriterSem.forced_release( 1 );
return;
}
else
continue;
if( (cmp & WAITING_READERS_MASK) != 0 )
[[unlikely]]
{
uint64_t wakeups = (cmp & WAITING_READERS_MASK) >> WAITING_READERS_BASE;
if( m_atomic.compare_exchange_weak( cmp, (cmp & ~WRITER_FLAG_MASK) - (cmp & WAITING_READERS_MASK) + wakeups, memory_order_release, memory_order_relaxed ) )
[[likely]]
{
m_releaseReadersSem.forced_release( (unsigned)wakeups );
return;
}
else
continue;
}
if( m_atomic.compare_exchange_weak( cmp, 0, memory_order_release, memory_order_relaxed ) )
[[likely]]
return;
}
}
bool wprio_shared_mutex::we_are_writer()
{
return (m_atomic.load( std::memory_order_relaxed ) & WRITER_FLAG_MASK) && m_writerId == std::this_thread::get_id();
}
The algorithm allows continuing readers, but as soon as a writer registers for writing, further readers are enqueued and the current readers are waited to be finished; and this is all done though a single 64 bit atomic value!
The code allows reader- as well as writer-recursion. But when you are reader multiple times, you shouldn't do shared_to_write(); you'll get a deadlock then. The ability to have recursion comes by nature for shared reading and has no extra-overhead. But for writing there's an additional recursion-counter as well as a thread::id.
I'm not going to include my semaphore-class here as it should self-explanatory. With my semaphore-class I have forced_wait and forced_release; this are two functions which repeatedly do a wait or release if it fails.
The [[likely]]- and [[unlikely]]-tags are C++20 optimization-hints. You can remove them with earlier compilers. The we_are_writer-method checks if the current thread has write-ownership. This could be used f.e. for debugging-purposes with assert().
The shared-mutex is aligned to cachelines through the alignas()-directive. But the whole object itself may be larger than a cacheline because of the two semaphores at the end of the object. But the data for the short locking-path is at the header which fits into a cacheline. It shouldn't hurt if the semaphores at the end of the object don't fit into the same cacheline since sleepy locking is slow anyay.
The object isn't neither copyable, nor moveable because the semaphore might not be also. This might be f.e. because POSIX-semaphores rely on a non-copyable sem_t-datatype which might me directly embedded in a C++ semaphore-datatype and thereby make it non-copy or -moveable.

How to get the number of remaining threads after terminating a thread in windows thread? c++

After terminating each thread using the below program, I need to print the remaining threads with ids every time, for which I am using GetExitCodeThread function but it is returning some garbage value.What could I be doing wrong?Also, how to print the remaining threads after getting the exitCode correct?
#define NUM_THREADS 10
#include <windows.h>
#include <stdio.h>
#include <process.h>
typedef struct
{
int Id;
HANDLE hTerminate;
} ThreadArgs;
unsigned _stdcall ThreadFunc( void *pArgs )
{
LPDWORD exitCode;
HANDLE hTerminate = ((ThreadArgs *)pArgs)->hTerminate;
int id = ((ThreadArgs *)pArgs)->Id;
// run until we are told to terminate while (1)
while(1)
{
// Check to see if we should terminate
if (WaitForSingleObject(hTerminate, 0) == WAIT_OBJECT_0)
{
// Terminate Thread - we call ResetEvent to
// return the terminate thread to its non-
// signaled state, then exit the while() loop
printf ("Terminating Thread %d\n", id);
GetExitCodeThread(hTerminate,exitCode);
printf("%d",exitCode);
ResetEvent(hTerminate);
break;
}
// we can do our work now ...
// simulate the case that it takes
// to do the work the thread has to do
Sleep(1000);
}
_endthreadex(0);
return 0;
}
int main(int argc, char* argv[])
{
int i=0;
unsigned int threadID[NUM_THREADS];
HANDLE hThread[NUM_THREADS];
ThreadArgs threadArgs[NUM_THREADS];
// Create 10 threads
printf("Total number of threads= %d\n", NUM_THREADS);
for (i = 0; i < NUM_THREADS;i++)
{
printf("Thread number %d \n",i);
}
for (int i = 0; i<NUM_THREADS;i++)
{
threadArgs[i].Id = i;
threadArgs[i].hTerminate = CreateEvent(NULL,TRUE,FALSE,NULL);
hThread[i] = (HANDLE)_beginthreadex(NULL,0,&ThreadFunc,&threadArgs[i], 0, &threadID[i]);
}
printf("To kill a thread (gracefully), press 0-9, "" then <Enter>. \n");
printf("Press any other key to exit.\n");
while (1)
{
int c = getc(stdin);
if (c == '\n')
continue;
if (c < '0' || c > '9')
break;
SetEvent(threadArgs[c -'0'].hTerminate);
}
return 0;
}
GetExitCodeThread() expects a HANDLE to a thread object, but you are passing it a HANDLE to an event object instead. You are also passing it an uninitialized pointer to write the exit code to. As such, GetExitCodeThread() is goes to fail with an error that you are ignoring, and the exit code will not be assigned any meaningful value.
Not that it matters, because GetExitCodeThread() is useless to call inside a thread that is still running, it will set the exit code to STILL_ACTIVE. You are supposed to call GetExitCodeThread() in a different thread than the one that is being terminated.
Try something more like this instead:
#include <windows.h>
#include <stdio.h>
#include <process.h>
#define MAX_THREADS 10
typedef struct
{
int Id;
DWORD dwThreadId;
HANDLE hThread;
HANDLE hTerminate;
} ThreadArgs;
unsigned __stdcall ThreadFunc( void *arg )
{
ThreadArgs *pArgs = (ThreadArgs *) arg;
// run until we are told to terminate while (1)
while(1)
{
// Check to see if we should terminate
if (WaitForSingleObject(pArgs->hTerminate, 0) == WAIT_OBJECT_0)
{
// Terminate Thread - exit the while() loop
printf ("Thread %d terminate signal detected\n", pArgs->Id);
break;
}
// we can do our work now ...
// simulate the case that it takes
// to do the work the thread has to do
Sleep(1000);
}
return 0;
}
int main(int argc, char* argv[])
{
int i;
ThreadArgs threadArgs[MAX_THREADS];
int numThreadsRunning = 0;
memset(&ThreadArgs, 0, sizeof(ThreadArgs));
// Create 10 threads
printf("Creating %d threads\n", MAX_THREADS);
for (i = 0; i < MAX_THREADS; ++i)
{
printf("Thread number %d: ", i);
threadArgs[i].Id = i;
threadArgs[i].hTerminate = CreateEvent(NULL, TRUE, FALSE, NULL);
threadArgs[i].hThread = (HANDLE) _beginthreadex(NULL, 0, &ThreadFunc, &threadArgs[i], 0, &threadArgs[i].dwThreadId);
if (threadArgs[i].hThread != NULL)
{
printf("Created\n");
++numThreadsRunning;
}
else
printf("Not Created!\n");
}
printf("Threads running: %d\n", numThreadsRunning);
printf("To kill a thread (gracefully), press 0-%d, then <Enter>.\n", MAX_THREADS-1);
printf("Press any other key to exit.\n");
while (1)
{
int c = getc(stdin);
if (c == '\n')
continue;
if ((c < '0') || (c > '9'))
break;
int id = c - '0';
if (threadArgs[id].hThread != NULL)
{
printf ("Signaling Thread %d to Terminate\n", id);
SetEvent(threadArgs[id].hTerminate);
WaitForSingleObject(threadArgs[id].hThread, INFINITE);
DWORD exitCode = 0;
GetExitCodeThread(threadArgs[id].hThread, &exitCode);
CloseHandle(threadArgs[id].hThread);
threadArgs[id].hThread = NULL;
printf ("Thread %d Terminated. Exit Code: %u\n", id, exitCode);
--numThreadsRunning;
printf ("Threads still running: %d\n", numThreadsRunning);
}
else
printf ("Thread %d is not running\n", id);
}
if (numThreadsRunning > 0)
{
printf ("Signaling remaining Threads to Terminate\n");
HANDLE hThreads[MAX_THREADS];
DWORD numThreads = 0;
for (i = 0; i < MAX_THREADS; ++i)
{
if (threadArgs[i].hThread != NULL)
{
hThreads[numThreads] = threadArgs[i].hThread;
++numThreads;
SetEvent(threadArgs[i].hTerminate);
}
}
WaitForMultipleObjects(numThreads, hThreads, TRUE, INFINITE);
for (i = 0; i < MAX_THREADS; ++i)
{
if (hThreads[i].hThread)
CloseHandle(hThreads[i].hThread);
if (hThreads[i].hTerminate)
CloseHandle(hThreads[i].hTerminate);
}
printf ("Threads Terminated\n");
}
return 0;
}
Have a look at this msdn article:
Traversing the Thread List
https://msdn.microsoft.com/en-us/library/windows/desktop/ms686852(v=vs.85).aspx
There is sample code on how to list the threads for a process.
~snip
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
// Forward declarations:
BOOL ListProcessThreads( DWORD dwOwnerPID );
void printError( TCHAR* msg );
int main( void )
{
ListProcessThreads(GetCurrentProcessId() );
return 0;
}
BOOL ListProcessThreads( DWORD dwOwnerPID )
{
HANDLE hThreadSnap = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// Take a snapshot of all running threads
hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
if( hThreadSnap == INVALID_HANDLE_VALUE )
return( FALSE );
// Fill in the size of the structure before using it.
te32.dwSize = sizeof(THREADENTRY32 );
// Retrieve information about the first thread,
// and exit if unsuccessful
if( !Thread32First( hThreadSnap, &te32 ) )
{
printError( TEXT("Thread32First") ); // Show cause of failure
CloseHandle( hThreadSnap ); // Must clean up the snapshot object!
return( FALSE );
}
// Now walk the thread list of the system,
// and display information about each thread
// associated with the specified process
do
{
if( te32.th32OwnerProcessID == dwOwnerPID )
{
_tprintf( TEXT("\n THREAD ID = 0x%08X"), te32.th32ThreadID );
_tprintf( TEXT("\n base priority = %d"), te32.tpBasePri );
_tprintf( TEXT("\n delta priority = %d"), te32.tpDeltaPri );
}
} while( Thread32Next(hThreadSnap, &te32 ) );
_tprintf( TEXT("\n"));
// Don't forget to clean up the snapshot object.
CloseHandle( hThreadSnap );
return( TRUE );
}
void printError( TCHAR* msg )
{
DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;
eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
sysMsg, 256, NULL );
// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );
// Display the message
_tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
}

pthread_cond_wait wake many threads example

pthread_cond_wait wake many threads example
Code to wake up thread 1 & 3 on some broadcast from thread 0.
Setup: Win7 with mingw32, g++ 4.8.1 with mingw32-pthreads-w32
pthread condition variable
Solution:
http://pastebin.com/X8aQ5Fz8
#include <iostream>
#include <string>
#include <list>
#include <map>
#include <pthread.h>
#include <fstream>
#include <sstream> // for ostringstream
#define N_THREAD 7
using namespace std;
// Prototypes
int main();
int scheduler();
void *worker_thread(void *ptr);
string atomic_output(int my_int, int thread_id);
// Global variables
//pthread_t thread0, thread1, thread2, thread3, thread4, thread5, thread6, thread7;
pthread_t m_thread[N_THREAD];
int count = 1;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
// Main
int main() {
cout << "Launching main. \n";
//Start to monitor for exceptions
register_exception_handler();
//Start scheduler
scheduler();
return 0;
}
// Scheduler
int scheduler() {
// Starting scheduler log file
ofstream scheduler_log;
scheduler_log.open ("scheduler_log.txt");
//scheduler_log << "[Scheduler] Starting." << endl;
cout << "[Scheduler] Starting. \n";
// Scheduler::Main Section
int thread_id[N_THREAD];
for(int i=0;i<N_THREAD;i++) {
thread_id[i] = i;
pthread_create( &m_thread[i], NULL, worker_thread, (void *) &thread_id[i]);
}
for(int i=0;i<N_THREAD;i++)
pthread_join(m_thread[i], NULL);
cout << "[Scheduler] Ending. \n";
// Closing scheduler log file
scheduler_log.close();
return 0;
}
string atomic_output(int my_int, int thread_id) {
ostringstream stm;
stm << "Thread ";
stm << thread_id;
stm << ": ";
//count fn
stm << my_int;
stm << "\n";
//stm << "Finished. \n";
return stm.str();
}
void *worker_thread(void *ptr) {
string line;
//int boo = 0;
int thread_id = *(int *) ptr;
//if(thread_id == 0)
// pthread_mutex_lock( &count_mutex );
for(int i=0;i<10;i++) {
//boo++;
if (thread_id == 1) {
pthread_mutex_lock(&count_mutex);
while (count == 1) {
cout << "[Thread 1] Before pthread_cond_wait...\n";
pthread_cond_wait( &condition_var, &count_mutex );
cout << "[Thread 1] After pthread_cond_wait...\n";
}
pthread_mutex_unlock(&count_mutex);
}
if (thread_id == 3) {
pthread_mutex_lock(&count_mutex);
while (count == 1) {
cout << "[Thread 3] Before pthread_cond_wait...\n";
pthread_cond_wait( &condition_var, &count_mutex );
cout << "[Thread 3] After pthread_cond_wait...\n";
}
pthread_mutex_unlock(&count_mutex);
}
//count fn
line = atomic_output(i, *(int *)ptr);
cout << line;
if (i == 5) {
if(thread_id == 0) {
pthread_mutex_lock( &count_mutex );
count = 0;
pthread_mutex_unlock( &count_mutex );
pthread_cond_broadcast(&condition_var);
}
}
}
//line = atomic_output(0, *(int *)ptr);
//cout << line;
}
(old) -= What I've tried =-
*Edit: early problem in the code with while(0) instead of while(predicate). Keeping it there for easy reference with the comments.
Code 1: http://pastebin.com/rCbYjPKi
I tried to while(0) pthread_cond_wait( &condition_var, &count_mutex );
with pthread_cond_broadcast(&condition_var); ... The thread does not respect the condition.
Proof of condition non-respect : http://pastebin.com/GW1cg4fY
Thread 0: 0
Thread 0: 1
Thread 0: 2
Thread 0: 3
Thread 2: 0
Thread 6: 0
Thread 1: 0 <-- Here, Thread 1 is not supposed to tick before Thread 0 hit 5. Thread 0 is at 3.
Code 2: http://pastebin.com/g3E0Mw9W
I tried pthread_cond_wait( &condition_var, &count_mutex ); in thread 1 and 3 and the program does not return.
either thread 1, or thread 3 waits forever. Even using broadcast which says it should wake up all waiting threads. Obviously something is not working, code or lib?
More:
I've tried to unlock the mutex first, then broadcast. I've tried to broadcast then unlock. Both don't work.
I've tried to use signal instead of broadcast, same problem.
References that I can't make work (top google search)
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032r/index.html
http://www-01.ibm.com/support/knowledgecenter/ssw_i5_54/apis/users_76.htm
Code 3: http://pastebin.com/tKP7F8a8
Trying to use a predicate variable count, to fix race problem condition. Still a problem, doesn't prevent thread1 and thread3 from running when thread0 is between 0 and 5.
What would be the code to wake up thread 1 & 3 on some function call from thread0
if(thread_id == 0)
pthread_mutex_lock( &count_mutex );
for(int i=0;i<10;i++) {
//boo++;
if (thread_id == 1) {
while(0)
pthread_cond_wait( &condition_var, &count_mutex );
}
None of this makes any sense. The correct way to wait for a condition variable is:
pthread_mutex_lock(&mutex_associated_with_condition_variable);
while (!predicate)
pthread_cond_wait(&condition_variable, mutex_associated_with_condition_variable);
Notice:
The mutex must be locked.
The predicate (thing you are waiting for) must be checked before waiting.
The wait must be in a loop.
Breaking any of these three rules will cause the kind of problems you are seeing. Your main problem is that you break the second rule, waiting even when the thing you want to wait for has already happened.

pthread windows crash C++

I would like to create an array of length 50 with a thread, when this is done I would like to print some of the first values in every X seconds with a second thread. In the meanwhile the first thread can compute the next array.
The threads are functional until I try to copy some values from the computed array in some temporary variables. I have no compilation error but when I run the program I get a windows crash massage.
Without threads the double *newarray(); function works. Returns an array which was manually allocated and filled with data.
What am I missing here?
Thread 1:
double *newarray();
void *computingU(void *)
{
double * U_tmp;
while (true)
{
pthread_mutex_lock( &mutexU );
memcpy(U_tmp,newarray(),sizeof(double)*Ulenght);
while (!Usent);
Usent = false;
memcpy(Ucmd,U_tmp,sizeof(double)*Ulenght);
pthread_mutex_unlock( &mutexU );
Ucomputed = true;
}
}
Thread 2:
void *sendingCMD(void * ) {
double * U_tmp;
while (true)
{
while (!Ucomputed);
Ucomputed = false;
pthread_mutex_lock( &mutexU );
memcpy(U_tmp,Ucmd,sizeof(double)*Ulenght);
pthread_mutex_unlock( &mutexU );
Usent = true;
for (int i = 0; i<Ulenght; i++)
{
printf("i= %d, u= %f", i, U_tmp[i]);
sleep(sleepTime) ;
}
}
}
Main:
#include <pthread.h>
#include <time.h>
#include <math.h>
#include <unistd.h>
using namespace std;
bool Ucomputed = false, Usent = true;
double * Ucmd;
pthread_mutex_t mutexU = PTHREAD_MUTEX_INITIALIZER;
unsigned int Ulenght = 1;
int sleepTime = 1;
int main( void )
{
#ifdef DEBUG_THREAD
int rc1, rc2;
pthread_t thread1, thread2;
/* Create independent threads each of which will execute functionC */
if( (rc1=pthread_create( &thread1, NULL, &computingU, NULL)) ) {
printf("Thread creation failed: %d\n", rc1);
}
if( (rc2=pthread_create( &thread2, NULL, &sendingCMD, NULL)) )
{
printf("Thread creation failed: %d\n", rc2);
}
#endif //
sleep(10);
while (true);
}
Lets take the first thread in the computingU function, there you have a local variable:
double * U_tmp;
Later you use this variable:
memcpy(U_tmp,newarray(),sizeof(double)*Ulenght);
But nowhere do you initialize the variable, so it doesn't point to anything. As uninitialized (non-static) local variables have indeterminate value, so the pointer U_tmp will point to a seemingly random location. Writing there will lead to undefined behavior and most likely your crash.
And you have the same problem in the other thread.
Look at:
double * U_tmp;
You never set the pointer to anything, and then attempt to memcpy() data into it. That will 100% crash every time. If it doesn't your OS is broken.