how to block a thread and resume it - c++

Here is what I want to do: there is a main thread producing numbers and put them into a queue, it fires a child thread consuming the numbers in the queue.
The main thread should stop producing numbers if the queue's size grows more than 10, and it should resume number production if the queue's size goes down less than 5.
queue<int> qu;
void *num_consumer(void *arg)
{
while(1) {
//lock qu
int num = qu.pop();
//unlock qu
do_something_with(num);
}
}
int main()
{
pthread_create(&tid, NULL, num_consumer, NULL);
while(1) {
int num;
produce(&num);
//lock qu
queue.push(num);
//unlock qu
if(qu.size() >= 10) {
//how to block and how to resume the main thread?
}
}
}
I might use semaphore to do the job, but any other idea?

A condition variable is appropriate here- actually, a pair of condition variables, because the consumer also needs to block if the queue is empty:
pthread_cond_t qu_empty_cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t qu_full_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qu_mutex = PTHREAD_MUTEX_INITIALIZER;
void *num_consumer(void *arg)
{
while(1) {
int num;
pthread_mutex_lock(&qu_mutex);
while (qu.size() < 1)
pthread_cond_wait(&qu_empty_cond, &qu_mutex);
num = qu.pop();
if (qu.size() < 5)
pthread_cond_signal(&qu_full_cond);
pthread_mutex_unlock(&qu_mutex);
do_something_with(num);
}
}
int main()
{
pthread_create(&tid, NULL, num_consumer, NULL);
while(1) {
int num;
produce(&num);
pthread_mutex_lock(&qu_mutex);
queue.push(num);
pthread_cond_signal(&qu_empty_cond);
if (qu.size() >= 10)
do {
pthread_cond_wait(&qu_full_cond, &qu_mutex);
} while (qu.size() >= 5);
pthread_mutex_unlock(&qu_mutex);
}
}
Note that that when the producer waits on the condition variable, the queue mutex is atomically released.

Related

Where to place pthread mutex and con var to ensure all functions are activated?

I have the following program that should take in "orders" and process them synchronously. I think most of it works, however critical region 4 doesn't get the mutex until after all of the orders are placed. Where should the cond_vars be placed so that region 4 gets the lock while orders are still being produced?
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <cstdlib>
using namespace std;
#define MAX 10
#define N 4
// Data structure to represent a simplified Order
// that has an order number and an item number.
struct Order
{
int order_num;
int item_num;
};
Order new_orders [N]; // array of elements of type Order to be used as
a shared buffer
int num_new_orders = 0; // count of number of new (i.e., unprocessed)
orders
int order_num = 0; // global variable used to generate unique order
numbers
pthread_mutex_t data_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t console_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t spaceAvailabe = PTHREAD_COND_INITIALIZER;
pthread_cond_t newOrder = PTHREAD_COND_INITIALIZER;
pthread_cond_t consoleVar = PTHREAD_COND_INITIALIZER;
void* takeOrders(void* arg)
{
int item;
int index = 0;
for(int i = 0; i < MAX; ++i) {
// Beginning of critical region 1
pthread_mutex_lock(&console_mutex);
// Get user input
cout << "Enter a menu item number between 1 and 50: ";
cin >> item;
// Print new order's details
cout << "Got new order! Order number is " << order_num <<
" and item number: " << item << std::endl;
// End of critical region 1
pthread_mutex_unlock(&console_mutex);
// Beginning of critical region 2
pthread_mutex_lock(&data_mutex);
// Put new order into new orders buffer and update number of new orders
while(num_new_orders>=MAX){
pthread_cond_wait(&spaceAvailabe, &console_mutex);
}
new_orders[index].order_num = order_num;
new_orders[index++].item_num = item;
++num_new_orders;
pthread_cond_signal(&newOrder);
// End of critical region 2
pthread_mutex_unlock(&data_mutex);
// Update order number so that next order gets a different number
++order_num;
// If the end of the new orders buffer is reached, wrap back around
if(index == N)
index = 0;
}
pthread_exit(NULL);
}
void* processOrders(void* arg)
{
int item;
int index = 0;
int o_num;
for(int i = 0; i < MAX; ++i) {
// Beginning of critical region 3
pthread_mutex_lock(&data_mutex);
// Retrieve new order details from buffer and update number of new orders
while(num_new_orders==0)
{
pthread_cond_wait(&newOrder, &data_mutex);
}
o_num = new_orders[index].order_num;
item = new_orders[index++].item_num;
--num_new_orders;
pthread_cond_signal(&spaceAvailabe);
// End of critical region 3
pthread_mutex_unlock(&data_mutex);
// Beginning of critical region 4
pthread_mutex_lock(&console_mutex);
// Print retrieved order's details
cout << "Processing order number " << o_num << " with item number: " <<
item << std::endl;
// End of critical region 4
pthread_mutex_unlock(&console_mutex);
// Suspend self for 1 second
sleep(1);
// If the end of the new orders buffer is reached, wrap back around
if(index == N)
index = 0;
}
pthread_exit(NULL);
}
int main()
{
// Create threads to take and process orders
pthread_t id1, id2;
pthread_create(&id1, NULL, processOrders, NULL);
pthread_create(&id2, NULL, takeOrders, NULL);
pthread_join(id1, NULL);
pthread_join(id2, NULL);
// Print goodbye message
cout << "Phew! Done with orders for today!" << endl;
pthread_exit(NULL);
}
I have written a program couple of months back How to execute thread in sync order. I am posting the same program here. Which might help you. Also do not mix C++ code with C. Better use stdio.h instead of iostream. In C++ 11 implementation of thread is much easier than C.
pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond3 = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock3 = PTHREAD_MUTEX_INITIALIZER;
int TRUE = 1;
void print(char *p)
{
printf("%s",p);
}
void * threadMethod1(void *arg)
{
printf("In thread1\n");
do{
pthread_mutex_lock(&lock1);
pthread_cond_wait(&cond1, &lock1);
print("I am thread 1st\n");
pthread_cond_signal(&cond3);/* Now allow 3rd thread to process */
pthread_mutex_unlock(&lock1);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod2(void *arg)
{
printf("In thread2\n");
do
{
pthread_mutex_lock(&lock2);
pthread_cond_wait(&cond2, &lock2);
print("I am thread 2nd\n");
pthread_cond_signal(&cond1);
pthread_mutex_unlock(&lock2);
}while(TRUE);
pthread_exit(NULL);
}
void * threadMethod3(void *arg)
{
printf("In thread3\n");
do
{
pthread_mutex_lock(&lock3);
pthread_cond_wait(&cond3, &lock3);
print("I am thread 3rd\n");
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&lock3);
}while(TRUE);
pthread_exit(NULL);
}
int main(void)
{
pthread_t tid1, tid2, tid3;
int i = 0;
printf("Before creating the threads\n");
if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 )
printf("Failed to create thread1\n");
if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 )
printf("Failed to create thread2\n");
if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 )
printf("Failed to create thread3\n");
pthread_cond_signal(&cond1);/* Now allow first thread to process first */
/*
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);*/
sleep(1);
TRUE = 0;/* Stop all the thread */
sleep(3);
exit(0);
}

A semaphore implmentation with Peterson's N process algorithm

I need feedback on my code for following statement, am I on right path?
Problem statement:
a. Implement a semaphore class that has a private int and three public methods: init, wait and signal. The wait and signal methods should behave as expected from a semaphore and must use Peterson's N process algorithm in their implementation.
b. Write a program that creates 5 threads that concurrently update the value of a shared integer and use an object of semaphore class created in part a) to ensure the correctness of the concurrent updates.
Here is my working program:
#include <iostream>
#include <pthread.h>
using namespace std;
pthread_mutex_t mid; //muted id
int shared=0; //global shared variable
class semaphore {
int counter;
public:
semaphore(){
}
void init(){
counter=1; //initialise counter 1 to get first thread access
}
void wait(){
pthread_mutex_lock(&mid); //lock the mutex here
while(1){
if(counter>0){ //check for counter value
counter--; //decrement counter
break; //break the loop
}
}
pthread_mutex_unlock(&mid); //unlock mutex here
}
void signal(){
pthread_mutex_lock(&mid); //lock the mutex here
counter++; //increment counter
pthread_mutex_unlock(&mid); //unlock mutex here
}
};
semaphore sm;
void* fun(void* id)
{
sm.wait(); //call semaphore wait
shared++; //increment shared variable
cout<<"Inside thread "<<shared<<endl;
sm.signal(); //call signal to semaphore
}
int main() {
pthread_t id[5]; //thread ids for 5 threads
sm.init();
int i;
for(i=0;i<5;i++) //create 5 threads
pthread_create(&id[i],NULL,fun,NULL);
for(i=0;i<5;i++)
pthread_join(id[i],NULL); //join 5 threads to complete their task
cout<<"Outside thread "<<shared<<endl;//final value of shared variable
return 0;
}
You need to release the mutex while spinning in the wait loop.
The test happens to work because the threads very likely run their functions start to finish before there is any context switch, and hence each one finishes before the next one even starts. So you have no contention over the semaphore. If you did, they'd get stuck with one waiter spinning with the mutex held, preventing anyone from accessing the counter and hence release the spinner.
Here's an example that works (though it may still have an initialization race that causes it to sporadically not launch correctly). It looks more complicated, mainly because it uses the gcc built-in atomic operations. These are needed whenever you have more than a single core, since each core has its own cache. Declaring the counters 'volatile' only helps with compiler optimization - for what is effectively SMP, cache consistency requires cross-processor cache invalidation, which means special processor instructions need to be used. You can try replacing them with e.g. counter++ and counter-- (and same for 'shared') - and observe how on a multi-core CPU it won't work. (For more details on the gcc atomic ops, see https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/_005f_005fatomic-Builtins.html)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
class semaphore {
pthread_mutex_t lock;
int32_t counter;
public:
semaphore() {
init();
}
void init() {
counter = 1; //initialise counter 1 to get first access
}
void spinwait() {
while (true) {
// Spin, waiting until we see a positive counter
while (__atomic_load_n(&counter, __ATOMIC_SEQ_CST) <= 0)
;
pthread_mutex_lock(&lock);
if (__atomic_load_n(&counter, __ATOMIC_SEQ_CST) <= 0) {
// Someone else stole the count from under us or it was
// a fluke - keep trying
pthread_mutex_unlock(&lock);
continue;
}
// It's ours
__atomic_fetch_add(&counter, -1, __ATOMIC_SEQ_CST);
pthread_mutex_unlock(&lock);
return;
}
}
void signal() {
pthread_mutex_lock(&lock); //lock the mutex here
__atomic_fetch_add(&counter, 1, __ATOMIC_SEQ_CST);
pthread_mutex_unlock(&lock); //unlock mutex here
}
};
enum {
NUM_TEST_THREADS = 5,
NUM_BANGS = 1000
};
// Making semaphore sm volatile would be complicated, because the
// pthread_mutex library calls don't expect volatile arguments.
int shared = 0; // Global shared variable
semaphore sm; // Semaphore protecting shared variable
volatile int num_workers = 0; // So we can wait until we have N threads
void* fun(void* id)
{
usleep(100000); // 0.1s. Encourage context switch.
const int worker = (intptr_t)id + 1;
printf("Worker %d ready\n", worker);
// Spin, waiting for all workers to be in a runnable state. These printouts
// could be out of order.
++num_workers;
while (num_workers < NUM_TEST_THREADS)
;
// Go!
// Bang on the semaphore. Odd workers increment, even decrement.
if (worker & 1) {
for (int n = 0; n < NUM_BANGS; ++n) {
sm.spinwait();
__atomic_fetch_add(&shared, 1, __ATOMIC_SEQ_CST);
sm.signal();
}
} else {
for (int n = 0; n < NUM_BANGS; ++n) {
sm.spinwait();
__atomic_fetch_add(&shared, -1, __ATOMIC_SEQ_CST);
sm.signal();
}
}
printf("Worker %d done\n", worker);
return NULL;
}
int main() {
pthread_t id[NUM_TEST_THREADS]; //thread ids
// create test worker threads
for(int i = 0; i < NUM_TEST_THREADS; i++)
pthread_create(&id[i], NULL, fun, (void*)((intptr_t)(i)));
// join threads to complete their task
for(int i = 0; i < NUM_TEST_THREADS; i++)
pthread_join(id[i], NULL);
//final value of shared variable. For an odd number of
// workers this is the loop count, NUM_BANGS
printf("Test done. Final value: %d\n", shared);
const int expected = (NUM_TEST_THREADS & 1) ? NUM_BANGS : 0;
if (shared == expected) {
puts("PASS");
} else {
printf("Value expected was: %d\nFAIL\n", expected);
}
return 0;
}

Pthread query: Sequence of threads error

#include<pthread.h>
#include<stdio.h>
int num_threads=3;
int state=0;
pthread_cond_t cond;
pthread_mutex_t mutex;
void* threadA(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 1 || state == 2) pthread_cond_wait(&cond,&mutex);
printf("Thread A\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void* threadB(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 0 || state == 2)pthread_cond_wait(&cond,&mutex);
printf("Thread B\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
void* threadC(void* args) {
int i;
for(i=0; i<5; i++){
pthread_mutex_lock(&mutex);
while(state == 1 || state == 0) pthread_cond_wait(&cond,&mutex);
printf("Thread C\n\n");
state = (state+1)%num_threads;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
}
int main() {
pthread_t tid[3];
pthread_cond_init(&cond,NULL);
pthread_mutex_init(&mutex,NULL);
pthread_create(&tid[0],NULL,threadA,NULL);
pthread_create(&tid[1],NULL,threadB,NULL);
pthread_create(&tid[2],NULL,threadC,NULL);
return 0;
}
QUESTION: With the above code, I wish to print
threaA threadB threadC sequentially 5 times.
But the answer is undeterministic. While the order
of threads is maintained, answers are not printed 5 times.
Please help!!!
As #mch mentioned in the comment, you need to wait for the threads to finish before allowing the main() function to return:
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
Now, after you add the joins above to the end of main(), your program will most often hang. This happens because the pthread_cond_signal() doesn't wake up all threads waiting on that condition variable. If the wrong thread is woke up (e.g. threadC signals the condition, but the thread that gets notified is not threadA), then all threads will be waiting on the condition and there will be nobody to signal that condition.
To fix this, you need to make sure all threads are woke up each time and let each thread decide on it's own if it is its turn or not (by that while(state...) pthread_cond_wait(...);). To do this, you can replace the calls to pthread_cond_signal() with calls to pthread_cond_broadcast(), which unblocks all threads currently blocked on that condition.

C++ Using semaphores instead of busy waiting

I am attempting to learn about semaphores and multi-threading. The example I am working with creates 1 to t threads with each thread pointing to the next and the last thread pointing to the first thread. This program allows each thread to sequentially take a turn until all threads have taken n turns. That is when the program ends. The only problem is in the tFunc function, I am busy waiting until it is a specific thread's turn. I want to know how to use semaphores in order to make all the threads go to sleep and waking up a thread only when it is its turn to execute to improve efficiency.
int turn = 1;
int counter = 0;
int t, n;
struct tData {
int me;
int next;
};
void *tFunc(void *arg) {
struct tData *data;
data = (struct tData *) arg;
for (int i = 0; i < n; i++) {
while (turn != data->me) {
}
counter++;
turn = data->next;
}
}
int main (int argc, char *argv[]) {
t = atoi(argv[1]);
n = atoi(argv[2]);
struct tData td[t];
pthread_t threads[t];
int rc;
for (int i = 1; i <= t; i++) {
if (i == t) {
td[i].me = i;
td[i].next = 1;
}
else {
td[i].me = i;
td[i].next = i + 1;
}
rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(-1);
}
}
for (int i = 1; i <= t; i++) {
pthread_join(threads[i], NULL);
}
pthread_exit(NULL);
}
Uses mutexes and condition variables. Here's a working example:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int turn = 1;
int counter = 0;
int t, n;
struct tData {
int me;
int next;
};
pthread_mutex_t mutex;
pthread_cond_t cond;
void *tFunc(void *arg)
{
struct tData *data;
data = (struct tData *) arg;
pthread_mutex_lock(&mutex);
for (int i = 0; i < n; i++)
{
while (turn != data->me)
pthread_cond_wait(&cond, &mutex);
counter++;
turn = data->next;
printf("%d goes (turn %d of %d), %d next\n", data->me, i+1, n, turn);
pthread_cond_broadcast(&cond);
}
pthread_mutex_unlock(&mutex);
}
int main (int argc, char *argv[]) {
t = atoi(argv[1]);
n = atoi(argv[2]);
struct tData td[t + 1];
pthread_t threads[t + 1];
int rc;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
for (int i = 1; i <= t; i++)
{
td[i].me = i;
if (i == t)
td[i].next = 1;
else
td[i].next = i + 1;
rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
if (rc)
{
printf("Error: Unable to create thread: %d\n", rc);
exit(-1);
}
}
void *ret;
for (int i = 1; i <= t; i++)
pthread_join(threads[i], &ret);
}
Use N+1 semaphores. On startup, thread i waits on semaphore i. When woken up it "takes a turnand signals semaphorei + 1`.
The main thread spawns the N, threads, signals semaphore 0 and waits on semaphore N.
Pseudo code:
sem s[N+1];
thread_proc (i):
repeat N:
wait (s [i])
do_work ()
signal (s [i+1])
main():
for i in 0 .. N:
spawn (thread_proc, i)
repeat N:
signal (s [0]);
wait (s [N]);
Have one semaphore per thread. Have each thread wait on its semaphore, retrying if sem_wait returns EINTR. Once it's done with its work, have it post to the next thread's semaphore. This avoids the "thundering herd" behaviour of David's solution by waking only one thread at a time.
Also notice that, since your semaphores will never have a value larger than one, you can use a pthread_mutex_t for this.

producer & consumer - multithreading

I wrote a multithreading program like this,
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
using namespace std;
pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t ec = PTHREAD_COND_INITIALIZER;
pthread_cond_t fc = PTHREAD_COND_INITIALIZER;
queue<int> qu;
const int N = 2;
void *producer(void *arg)
{
while(1) {
pthread_mutex_lock(&mu);
int tmp = rand();
qu.push(tmp);
pthread_cond_signal(&ec);
if ((int) qu.size() > N) {
pthread_cond_wait(&fc, &mu);
}
pthread_mutex_unlock(&mu);
}
}
void *consumer(void *arg)
{
while(1) {
pthread_mutex_lock(&mu);
if ((int) qu.size() < 1) {
pthread_cond_wait(&ec, &mu);
}
int tmp = qu.front();
qu.pop();
if ((int) qu.size() <= N) {
pthread_cond_signal(&fc);
}
pthread_mutex_unlock(&mu);
//sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, producer, NULL);
for (int i = 0; i < N; i++) {
pthread_t tid;
pthread_create(&tid, NULL, consumer, NULL);
}
printf("all created\n");
sleep(600);
}
When the qu.size() is geater than N, producer should stop producing, and when it's less than N, producer resumes producing.
The weired problem is, if I remove the sleep(1); in consumer, the program will run into segmentation fault, if I keep sleep(1);, the program runs ok.
Why? Does it mean the consumer consumes too fast?
Spurious wakeup might be the reason. Your thread will proceed if the condition is true, but if your thread proceeds you can't assume the condition is true.
Spurious wakeups from the pthread_cond_timedwait() or pthread_cond_wait() functions may occur. Since the return from pthread_cond_timedwait() or pthread_cond_wait() does not imply anything about the value of this predicate, the predicate should be re-evaluated upon such return.
So for example
if (qu.size() == 0) {
pthread_cond_wait(&ec, &mu);
}
should become
while (qu.size() == 0) {
pthread_cond_wait(&ec, &mu);
}
If you keep the sleep(1) call and the whole thing does not crash you're just lucky :)
Try initializing the mutex explicitly using the pthread_mutex_init() otherwise your pthread_mutex_lock() calls seem to fail.
From the docs:
Errors
The pthread_mutex_lock() and pthread_mutex_trylock()
functions may fail if:
EINVAL: The value specified by mutex
does not refer to an initialized mutex object.