forked from OSchip/llvm-project
Convert all use of pthreads in tests to c++11 threads.
This eliminates portability issues among platforms that don't have a pthreads implementation. Differential Revision: http://reviews.llvm.org/D12043 Reviewed By: Greg Clayton llvm-svn: 245234
This commit is contained in:
parent
685a7d1a70
commit
8778fea0bb
|
@ -1,6 +1,6 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
C_SOURCES := locking.c
|
||||
CXX_SOURCES := locking.cpp
|
||||
ENABLE_THREADS := YES
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
|
|
@ -44,7 +44,7 @@ class ExprDoesntDeadlockTestCase(TestBase):
|
|||
|
||||
# Now create a breakpoint at source line before call_me_to_get_lock gets called.
|
||||
|
||||
main_file_spec = lldb.SBFileSpec ("locking.c")
|
||||
main_file_spec = lldb.SBFileSpec ("locking.cpp")
|
||||
breakpoint = target.BreakpointCreateBySourceRegex('Break here', main_file_spec)
|
||||
if self.TraceOn():
|
||||
print "breakpoint:", breakpoint
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
pthread_mutex_t contended_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
pthread_mutex_t control_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t control_condition;
|
||||
|
||||
pthread_mutex_t thread_started_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t thread_started_condition;
|
||||
|
||||
// This function runs in a thread. The locking dance is to make sure that
|
||||
// by the time the main thread reaches the pthread_join below, this thread
|
||||
// has for sure acquired the contended_mutex. So then the call_me_to_get_lock
|
||||
// function will block trying to get the mutex, and only succeed once it
|
||||
// signals this thread, then lets it run to wake up from the cond_wait and
|
||||
// release the mutex.
|
||||
|
||||
void *
|
||||
lock_acquirer_1 (void *input)
|
||||
{
|
||||
pthread_mutex_lock (&contended_mutex);
|
||||
|
||||
// Grab this mutex, that will ensure that the main thread
|
||||
// is in its cond_wait for it (since that's when it drops the mutex.
|
||||
|
||||
pthread_mutex_lock (&thread_started_mutex);
|
||||
pthread_mutex_unlock(&thread_started_mutex);
|
||||
|
||||
// Now signal the main thread that it can continue, we have the contended lock
|
||||
// so the call to call_me_to_get_lock won't make any progress till this
|
||||
// thread gets a chance to run.
|
||||
|
||||
pthread_mutex_lock (&control_mutex);
|
||||
|
||||
pthread_cond_signal (&thread_started_condition);
|
||||
|
||||
pthread_cond_wait (&control_condition, &control_mutex);
|
||||
|
||||
pthread_mutex_unlock (&contended_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
call_me_to_get_lock ()
|
||||
{
|
||||
pthread_cond_signal (&control_condition);
|
||||
pthread_mutex_lock (&contended_mutex);
|
||||
return 567;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
|
||||
pthread_cond_init (&control_condition, NULL);
|
||||
pthread_cond_init (&thread_started_condition, NULL);
|
||||
|
||||
pthread_mutex_lock (&thread_started_mutex);
|
||||
|
||||
pthread_create (&thread_1, NULL, lock_acquirer_1, NULL);
|
||||
|
||||
pthread_cond_wait (&thread_started_condition, &thread_started_mutex);
|
||||
|
||||
pthread_mutex_lock (&control_mutex);
|
||||
pthread_mutex_unlock (&control_mutex);
|
||||
|
||||
// Break here. At this point the other thread will have the contended_mutex,
|
||||
// and be sitting in its cond_wait for the control condition. So there is
|
||||
// no way that our by-hand calling of call_me_to_get_lock will proceed
|
||||
// without running the first thread at least somewhat.
|
||||
|
||||
call_me_to_get_lock();
|
||||
pthread_join (thread_1, NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
std::mutex contended_mutex;
|
||||
std::mutex control_mutex;
|
||||
std::mutex thread_started_mutex;
|
||||
|
||||
std::unique_lock<std::mutex> *contended_lock = nullptr;
|
||||
std::unique_lock<std::mutex> *control_lock = nullptr;
|
||||
std::unique_lock<std::mutex> *thread_started_lock = nullptr;
|
||||
|
||||
std::condition_variable control_condition;
|
||||
std::condition_variable thread_started_condition;
|
||||
|
||||
// This function runs in a thread. The locking dance is to make sure that
|
||||
// by the time the main thread reaches the pthread_join below, this thread
|
||||
// has for sure acquired the contended_mutex. So then the call_me_to_get_lock
|
||||
// function will block trying to get the mutex, and only succeed once it
|
||||
// signals this thread, then lets it run to wake up from the cond_wait and
|
||||
// release the mutex.
|
||||
|
||||
void *
|
||||
lock_acquirer_1 ()
|
||||
{
|
||||
contended_lock->lock();
|
||||
|
||||
// Grab this mutex, that will ensure that the main thread
|
||||
// is in its cond_wait for it (since that's when it drops the mutex.
|
||||
thread_started_lock->lock();
|
||||
thread_started_lock->unlock();
|
||||
|
||||
// Now signal the main thread that it can continue, we have the contended lock
|
||||
// so the call to call_me_to_get_lock won't make any progress till this
|
||||
// thread gets a chance to run.
|
||||
control_lock->lock();
|
||||
|
||||
thread_started_condition.notify_all();
|
||||
control_condition.wait(*control_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
call_me_to_get_lock ()
|
||||
{
|
||||
control_condition.notify_all();
|
||||
contended_lock->lock();
|
||||
return 567;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
contended_lock = new std::unique_lock<std::mutex>(contended_mutex, std::defer_lock);
|
||||
control_lock = new std::unique_lock<std::mutex>(control_mutex, std::defer_lock);
|
||||
thread_started_lock = new std::unique_lock<std::mutex>(thread_started_mutex, std::defer_lock);
|
||||
|
||||
thread_started_lock->lock();
|
||||
|
||||
std::thread thread_1(lock_acquirer_1);
|
||||
|
||||
thread_started_condition.wait(*thread_started_lock);
|
||||
|
||||
control_lock->lock();
|
||||
control_lock->unlock();
|
||||
|
||||
// Break here. At this point the other thread will have the contended_mutex,
|
||||
// and be sitting in its cond_wait for the control condition. So there is
|
||||
// no way that our by-hand calling of call_me_to_get_lock will proceed
|
||||
// without running the first thread at least somewhat.
|
||||
|
||||
call_me_to_get_lock();
|
||||
thread_1.join();
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
// This test is intended to create a situation in which one thread will be
|
||||
// created while the debugger is stepping in another thread.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
// Note that although hogging the CPU while waiting for a variable to change
|
||||
// would be terrible in production code, it's great for testing since it
|
||||
|
@ -31,7 +31,7 @@ volatile int g_thread_created = 0;
|
|||
volatile int g_test = 0;
|
||||
|
||||
void *
|
||||
step_thread_func (void *input)
|
||||
step_thread_func ()
|
||||
{
|
||||
g_test = 0; // Set breakpoint here
|
||||
|
||||
|
@ -48,13 +48,13 @@ step_thread_func (void *input)
|
|||
void *
|
||||
create_thread_func (void *input)
|
||||
{
|
||||
pthread_t *step_thread = (pthread_t*)input;
|
||||
std::thread *step_thread = (std::thread*)input;
|
||||
|
||||
// Wait until the main thread knows this thread is started.
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
||||
// Wait until the other thread is done.
|
||||
pthread_join(*step_thread, NULL);
|
||||
step_thread->join();
|
||||
|
||||
// Return
|
||||
return NULL;
|
||||
|
@ -62,21 +62,18 @@ create_thread_func (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
|
||||
// Use a simple count to simulate a barrier.
|
||||
pseudo_barrier_init(g_barrier, 2);
|
||||
|
||||
// Create a thread to hit the breakpoint.
|
||||
pthread_create (&thread_1, NULL, step_thread_func, NULL);
|
||||
std::thread thread_1(step_thread_func);
|
||||
|
||||
// Wait until the step thread is stepping
|
||||
while (g_test < 1)
|
||||
do_nothing();
|
||||
|
||||
// Create a thread to exit while we're stepping.
|
||||
pthread_create (&thread_2, NULL, create_thread_func, &thread_1);
|
||||
std::thread thread_2(create_thread_func, &thread_1);
|
||||
|
||||
// Wait until that thread is started
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
@ -85,8 +82,8 @@ int main ()
|
|||
g_thread_created = 1;
|
||||
|
||||
// Wait for the threads to finish.
|
||||
pthread_join(thread_2, NULL);
|
||||
pthread_join(thread_1, NULL);
|
||||
thread_2.join();
|
||||
thread_1.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
// breakpoint is hit. The test case should be flexible enough to treat that
|
||||
// as success.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
volatile int g_test = 0;
|
||||
|
||||
|
@ -42,7 +42,7 @@ std::atomic_int g_barrier2;
|
|||
std::atomic_int g_barrier3;
|
||||
|
||||
void *
|
||||
break_thread_func (void *input)
|
||||
break_thread_func ()
|
||||
{
|
||||
// Wait until the entire first group of threads is running
|
||||
pseudo_barrier_wait(g_barrier1);
|
||||
|
@ -61,7 +61,7 @@ break_thread_func (void *input)
|
|||
}
|
||||
|
||||
void *
|
||||
wait_thread_func (void *input)
|
||||
wait_thread_func ()
|
||||
{
|
||||
// Wait until the entire first group of threads is running
|
||||
pseudo_barrier_wait(g_barrier1);
|
||||
|
@ -77,7 +77,7 @@ wait_thread_func (void *input)
|
|||
}
|
||||
|
||||
void *
|
||||
exit_thread_func (void *input)
|
||||
exit_thread_func ()
|
||||
{
|
||||
// Sync up with the rest of the threads.
|
||||
pseudo_barrier_wait(g_barrier2);
|
||||
|
@ -91,11 +91,6 @@ exit_thread_func (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
pthread_t thread_3;
|
||||
pthread_t thread_4;
|
||||
pthread_t thread_5;
|
||||
|
||||
// The first barrier waits for the non-exiting threads to start.
|
||||
// This thread will also participate in that barrier.
|
||||
|
@ -111,25 +106,25 @@ int main ()
|
|||
pseudo_barrier_init(g_barrier3, 4);
|
||||
|
||||
// Create a thread to hit the breakpoint
|
||||
pthread_create (&thread_1, NULL, break_thread_func, NULL);
|
||||
std::thread thread_1(break_thread_func);
|
||||
|
||||
// Create more threads to slow the debugger down during processing.
|
||||
pthread_create (&thread_2, NULL, wait_thread_func, NULL);
|
||||
pthread_create (&thread_3, NULL, wait_thread_func, NULL);
|
||||
pthread_create (&thread_4, NULL, wait_thread_func, NULL);
|
||||
std::thread thread_2(wait_thread_func);
|
||||
std::thread thread_3(wait_thread_func);
|
||||
std::thread thread_4(wait_thread_func);
|
||||
|
||||
// Wait for all these threads to get started.
|
||||
pseudo_barrier_wait(g_barrier1);
|
||||
|
||||
// Create a thread to exit during the breakpoint
|
||||
pthread_create (&thread_5, NULL, exit_thread_func, NULL);
|
||||
std::thread thread_5(exit_thread_func);
|
||||
|
||||
// Wait for the threads to finish
|
||||
pthread_join(thread_5, NULL);
|
||||
pthread_join(thread_4, NULL);
|
||||
pthread_join(thread_3, NULL);
|
||||
pthread_join(thread_2, NULL);
|
||||
pthread_join(thread_1, NULL);
|
||||
thread_5.join();
|
||||
thread_4.join();
|
||||
thread_3.join();
|
||||
thread_2.join();
|
||||
thread_1.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
// This test is intended to create a situation in which one thread will exit
|
||||
// while the debugger is stepping in another thread.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
// Note that although hogging the CPU while waiting for a variable to change
|
||||
// would be terrible in production code, it's great for testing since it
|
||||
// avoids a lot of messy context switching to get multiple threads synchronized.
|
||||
|
@ -33,7 +34,7 @@ volatile int g_thread_exited = 0;
|
|||
volatile int g_test = 0;
|
||||
|
||||
void *
|
||||
step_thread_func (void *input)
|
||||
step_thread_func ()
|
||||
{
|
||||
// Wait until both threads are started.
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
@ -51,7 +52,7 @@ step_thread_func (void *input)
|
|||
}
|
||||
|
||||
void *
|
||||
exit_thread_func (void *input)
|
||||
exit_thread_func ()
|
||||
{
|
||||
// Wait until both threads are started.
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
@ -66,26 +67,23 @@ exit_thread_func (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
|
||||
// Synchronize thread start so that doesn't happen during stepping.
|
||||
pseudo_barrier_init(g_barrier, 2);
|
||||
|
||||
// Create a thread to hit the breakpoint.
|
||||
pthread_create (&thread_1, NULL, step_thread_func, NULL);
|
||||
std::thread thread_1(step_thread_func);
|
||||
|
||||
// Create a thread to exit while we're stepping.
|
||||
pthread_create (&thread_2, NULL, exit_thread_func, NULL);
|
||||
std::thread thread_2(exit_thread_func);
|
||||
|
||||
// Wait for the exit thread to finish.
|
||||
pthread_join(thread_2, NULL);
|
||||
thread_2.join();
|
||||
|
||||
// Let the stepping thread know the other thread is gone.
|
||||
g_thread_exited = 1;
|
||||
|
||||
// Wait for the stepping thread to finish.
|
||||
pthread_join(thread_1, NULL);
|
||||
thread_1.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
// the breakpoint in the second thread will be hit while the breakpoint handler
|
||||
// in the first thread is trying to stop all threads.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
// Note that although hogging the CPU while waiting for a variable to change
|
||||
// would be terrible in production code, it's great for testing since it
|
||||
|
@ -32,7 +32,7 @@ std::atomic_int g_barrier;
|
|||
volatile int g_test = 0;
|
||||
|
||||
void *
|
||||
thread_func (void *input)
|
||||
thread_func ()
|
||||
{
|
||||
// Wait until both threads are running
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
@ -46,19 +46,16 @@ thread_func (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
|
||||
// Don't let either thread do anything until they're both ready.
|
||||
pseudo_barrier_init(g_barrier, 2);
|
||||
|
||||
// Create two threads
|
||||
pthread_create (&thread_1, NULL, thread_func, NULL);
|
||||
pthread_create (&thread_2, NULL, thread_func, NULL);
|
||||
std::thread thread_1(thread_func);
|
||||
std::thread thread_2(thread_func);
|
||||
|
||||
// Wait for the threads to finish
|
||||
pthread_join(thread_1, NULL);
|
||||
pthread_join(thread_2, NULL);
|
||||
thread_1.join();
|
||||
thread_2.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
// This test is intended to create a situation in which two threads are stopped
|
||||
// at a breakpoint and the debugger issues a step-out command.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
// Note that although hogging the CPU while waiting for a variable to change
|
||||
// would be terrible in production code, it's great for testing since it
|
||||
|
@ -34,7 +34,7 @@ void step_out_of_here() {
|
|||
}
|
||||
|
||||
void *
|
||||
thread_func (void *input)
|
||||
thread_func ()
|
||||
{
|
||||
// Wait until both threads are running
|
||||
pseudo_barrier_wait(g_barrier);
|
||||
|
@ -48,19 +48,16 @@ thread_func (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
|
||||
// Don't let either thread do anything until they're both ready.
|
||||
pseudo_barrier_init(g_barrier, 2);
|
||||
|
||||
// Create two threads
|
||||
pthread_create (&thread_1, NULL, thread_func, NULL);
|
||||
pthread_create (&thread_2, NULL, thread_func, NULL);
|
||||
std::thread thread_1(thread_func);
|
||||
std::thread thread_2(thread_func);
|
||||
|
||||
// Wait for the threads to finish
|
||||
pthread_join(thread_1, NULL);
|
||||
pthread_join(thread_2, NULL);
|
||||
thread_1.join();
|
||||
thread_2.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
// This test verifies the correct handling of child thread exits.
|
||||
|
||||
#include <pthread.h>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
// Note that although hogging the CPU while waiting for a variable to change
|
||||
// would be terrible in production code, it's great for testing since it
|
||||
|
@ -29,7 +29,7 @@ std::atomic_int g_barrier2;
|
|||
std::atomic_int g_barrier3;
|
||||
|
||||
void *
|
||||
thread1 (void *input)
|
||||
thread1 ()
|
||||
{
|
||||
// Synchronize with the main thread.
|
||||
pseudo_barrier_wait(g_barrier1);
|
||||
|
@ -42,7 +42,7 @@ thread1 (void *input)
|
|||
}
|
||||
|
||||
void *
|
||||
thread2 (void *input)
|
||||
thread2 ()
|
||||
{
|
||||
// Synchronize with thread1 and the main thread.
|
||||
pseudo_barrier_wait(g_barrier2);
|
||||
|
@ -56,34 +56,30 @@ thread2 (void *input)
|
|||
|
||||
int main ()
|
||||
{
|
||||
pthread_t thread_1;
|
||||
pthread_t thread_2;
|
||||
pthread_t thread_3;
|
||||
|
||||
pseudo_barrier_init(g_barrier1, 2);
|
||||
pseudo_barrier_init(g_barrier2, 3);
|
||||
pseudo_barrier_init(g_barrier3, 2);
|
||||
|
||||
// Create a thread.
|
||||
pthread_create (&thread_1, NULL, thread1, NULL);
|
||||
std::thread thread_1(thread1);
|
||||
|
||||
// Wait for thread1 to start.
|
||||
pseudo_barrier_wait(g_barrier1);
|
||||
|
||||
// Create another thread.
|
||||
pthread_create (&thread_2, NULL, thread2, NULL); // Set first breakpoint here
|
||||
std::thread thread_2(thread2); // Set first breakpoint here
|
||||
|
||||
// Wait for thread2 to start.
|
||||
pseudo_barrier_wait(g_barrier2);
|
||||
|
||||
// Wait for the first thread to finish
|
||||
pthread_join(thread_1, NULL);
|
||||
thread_1.join();
|
||||
|
||||
// Synchronize with the remaining thread
|
||||
pseudo_barrier_wait(g_barrier3); // Set third breakpoint here
|
||||
|
||||
// Wait for the second thread to finish
|
||||
pthread_join(thread_2, NULL);
|
||||
thread_2.join();
|
||||
|
||||
return 0; // Set fourth breakpoint here
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
C_SOURCES := main.c
|
||||
CXX_SOURCES := main.cpp
|
||||
ENABLE_THREADS := YES
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
|
|
@ -37,7 +37,7 @@ class ThreadSpecificBreakTestCase(TestBase):
|
|||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target, VALID_TARGET)
|
||||
|
||||
main_source_spec = lldb.SBFileSpec ("main.c")
|
||||
main_source_spec = lldb.SBFileSpec ("main.cpp")
|
||||
|
||||
# Set a breakpoint in the thread body, and make it active for only the first thread.
|
||||
break_thread_body = target.BreakpointCreateBySourceRegex ("Break here in thread body.", main_source_spec)
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void *
|
||||
thread_function (void *thread_marker)
|
||||
{
|
||||
int keep_going = 1;
|
||||
int my_value = *((int *)thread_marker);
|
||||
int counter = 0;
|
||||
|
||||
while (counter < 20)
|
||||
{
|
||||
counter++; // Break here in thread body.
|
||||
usleep (10);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
|
||||
pthread_t threads[10];
|
||||
|
||||
int thread_value = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
thread_value += 1;
|
||||
pthread_create (&threads[i], NULL, &thread_function, &thread_value);
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
pthread_join (threads[i], NULL);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
void *
|
||||
thread_function (void *thread_marker)
|
||||
{
|
||||
int keep_going = 1;
|
||||
int my_value = *((int *)thread_marker);
|
||||
int counter = 0;
|
||||
|
||||
while (counter < 20)
|
||||
{
|
||||
counter++; // Break here in thread body.
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
int thread_value = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
thread_value += 1;
|
||||
threads.push_back(std::thread(thread_function, &thread_value));
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
threads[i].join();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue