问题
Odd even number printing using thread I came across this question and wanted to discuss solution in C++ . What I can think of using 2 binary semaphores odd and even semaphore. even semaphore initialized to 1 and odd initialized to 0.
**T1 thread function**
funOdd()
{
wait(even)
print odd;
signal(odd)
}
**T2 thread function**
funEven()
{
wait(odd)
print even
signal(even)
}
In addition to this if my functions are generating only number and there is a third thread T3 which is going to print those numbers then what should be ideal design ? I used an array where odd number will be placed at odd place and even number will be place at even position. T3 will read from this array this will avoid any thread saftey over this array and if T3 does not find any index then it will wait till that index gets populated. Another solution can be to use a queue which will have a mutex which can be used by T1 and T2 while insertion.
Please comment on this solution and how can i make it more efficient.
Edit to make problem much clear: Overall problem is that I have two producers (T1,T2) and a single consumer (T3), and my producers are interdependent.
回答1:
Using condition_variable
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mu;
std::condition_variable cond;
int count = 1;
void PrintOdd()
{
for(; count < 100;)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker,[](){ return (count%2 == 1); });
std::cout << "From Odd: " << count << std::endl;
count++;
locker.unlock();
cond.notify_all();
}
}
void PrintEven()
{
for(; count < 100;)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker,[](){ return (count%2 == 0); });
std::cout << "From Even: " << count << std::endl;
count++;
locker.unlock();
cond.notify_all();
}
}
int main()
{
std::thread t1(PrintOdd);
std::thread t2(PrintEven);
t1.join();
t2.join();
return 0;
}
回答2:
Solution is based on C++11 critical code section aka mutex.
Here's the working code, followed by an explanation.
Tested and working on VS2013:
using namespace std;
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
std::mutex mtx;
void oddAndEven(int n, int end);
int main()
{
std::thread odd(oddAndEven, 1, 10);
std::thread Even(oddAndEven, 2, 10);
odd.join();
Even.join();
return 0;
}
void oddAndEven(int n, int end){
int x = n;
for (; x < end;){
mtx.lock();
std::cout << n << " - " << x << endl;
x += 2;
mtx.unlock();
std::this_thread::yield();
continue;
}
}
i.e:
Thread odd goes to method oddAndEven with starting number 1 thus he is the odd. He is the first to acquire the lock which is the mtx.lock().
Meanwhile, thread Even tries to acquire the lock too but thread odd acquired it first so thread Even waits.
Back to thread odd (which has the lock), he prints the number 1 and releases the lock with mtx.unlock(). At this moment, we want thread Even to acquire lock and to print 2 so we notify thread Even by writing std::this_thread::yield(). Then thread Even does the same.
etc etc etc.
回答3:
This is the easiest solution you can refer:
#include<iostream>
#include<mutex>
#include<pthread.h>
#include<cstdlib>
int count=0;
using namespace std;
mutex m;
void* printEven(void *a)
{
while(1)
{
m.lock();
if(count%2==0)
{
cout<<" I am Even"<<count<<endl;
count++;
}
if(count==100)
break;
m.unlock();
}
}
void* printOdd(void *b)
{
while(1)
{
m.lock();
if(count%2!=0)
{
cout<<"I am odd"<<count<<endl;
count++;
}
if(count>100)
break;
m.unlock();
}
}
int main()
{
int *ptr = new int();
pthread_t thread1, thread2;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&thread1,&attr,&printEven,NULL);
pthread_create(&thread2,&attr,&printOdd, NULL);
pthread_join(thread1,&ptr);
pthread_join(thread2,&ptr);
delete ptr;
}
回答4:
I fail to understand why you want to use three separate threads for a serial behavior. But I will answer anyway:)
One solution would be to use a modified producer/consumer pattern with a prioritized queue between producers and consumers. The sort operation on the queue would depend on the integer value of the posted message. The consumer would peek an element in the queue and check if it is the next expected element. If not, it would sleep/wait.
A bit of code:
class Elt implements Comparable<Elt> {
int value;
Elt(value) { this.value=value; }
int compare(Elt elt);
}
class EltQueue extends PriorityBlockingQueue<Elt> { // you shouldn't inherit colelctions, has-a is better, but to make it short
static EltQueue getInstance(); // singleton pattern
}
class Consumer{
Elt prevElt = new Elt(-1);
void work()
{
Elt elt = EltQueue.getInstance().peek();
if (elt.getValue() == prevElt.getValue()+1)) {
EltQueue.getInstance().poll();
//do work on Elt
}
}
}
class Producer {
int n=0; // or 1!
void work() {
EltQueue.getInstance().put(new Elt(n+=2));
}
}
回答5:
As a first thing, the two functions should a least contain a loop, (unless you just want a single number)
A more standard solution (which remaps your idea) is to have a global structure containing a a mutex, and two condition variables (odd and even) plus a return value, and another condition for the printing. than use a uique_lock to handle the synchronization.
IN PSEUDOCODE:
struct global_t
{
mutex mtx;
int value = {0};
condition_variable be_odd, be_even, print_it;
bool bye = {false};
global_t() { be_odd.notify(); }
} global;
void odd_generator()
{
int my_odd = 1;
for(;;)
{
unique_lock lock(global.mtx);
if(global.bye) return;
global.be_odd.wait(lock);
global_value = my_odd; my_odd+=2;
global.print_it.notify();
if(my_odd > 100) bye=true;
} //let RAII to manage wait states and unlocking
};
void even_generator()
{ /* same as odd, with inverted roles */ }
void printer()
{
for(;;)
{
unique_lock lock(global.mtx);
if(bye) return;
global.ptint_it.wait(lock);
std::cout << global.value << std::endl;
((global.value & 1)? global.be_even: global.be_odd).notify();
}
}
int main()
{
thread oddt(odd_generator), event(even_generator), printt(printer);
oddt.join(), event.join(), printer.join();
}
Note that, apart didactic purpose, this solution adds no value respect to a simple loop printing the value of a counter, since there will never be real concurrency.
Note also (to avoid globals) that you can wrap everything into a class (making the actual main a class method) and instantate that class on the stack inside the new main.
回答6:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;
sem_t sem2;
using namespace std ;
int count = 1;
void increment(int x)
{
cout << "called by thread : " << x << "count is : " << count ++ << "\n";
}
void *printAltmessage1(void *thread_value)
{
for(int m=0; m < (*(int *)thread_value); m++)
{
if (sem_wait(&sem) == 0)
{
cout << " Thread printAltmessage1 is executed" <<"\n";
increment(1);
sem_post(&sem2);
}
}
}
void *printAltmessage2(void *thread_value)
{
for(int m=0; m < (*(int *)thread_value); m++)
{
if (sem_wait(&sem2) == 0)
{
cout << " Thread printAltmessage2 is executed" <<"\n";
increment(2);
sem_post(&sem);
}
}
}
int main()
{
sem_init(&sem,0, 1);
sem_init(&sem2,0, 0);
pthread_t threads[2];
int x =8;
for(int i=0;i<2;i++)
{
if(i==0)
int rc =pthread_create(&threads[i],NULL,printAltmessage1,(void*)&x);
else
int rc =pthread_create(&threads[i],NULL,printAltmessage2,(void*)&x);
}
pthread_exit(NULL);
return 0;
}
回答7:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mu;
unsigned int change = 0;
void printConsecutiveNumbers(int start, int end,unsigned int consecutive)
{
int x = start;
while (x < end)
{
//each thread has check there time is coming or not
if (change % consecutive == start)
{
std::unique_lock<std::mutex> locker(mu);
std::cout << "Thread " << start << " -> " << x << std::endl;
x += consecutive;
change++;
//to counter overflow
change %= consecutive;
}
}
}
int main()
{
//change num = 2 for printing odd and even
const int num = 7;
const int endValue = 1000;
std::thread threads[num];
//Create each consecutive threads
for (int i = 0; i < num; i++)
{
threads[i] = std::thread(printConsecutiveNumbers, i, endValue, num);
}
//Joins all thread to the main thread
for (int i = 0; i < num; i++)
{
threads[i].join();
}
return 0;
}
回答8:
This is simple solution using single function.
#include <iostream>
#include <thread>
#include <condition_variable>
using namespace std;
mutex mu;
condition_variable cond;
int count = 1;
void PrintOddAndEven(bool even, int n){
while(count < n){
unique_lock<mutex> lk(mu);
cond.wait(lk, [&](){return count%2 == even;});
cout << count++ << " ";
lk.unlock();
cond.notify_all();
}
}
int main() {
int n = 10;
thread t1(PrintOddAndEven, true, n);
thread t2(PrintOddAndEven, false, n);
t1.join();
t2.join();
return 0;
}
回答9:
Please see below working code (VS2005)
#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <process.h>
#define MAX 100
int shared_value = 0;
CRITICAL_SECTION cs;
unsigned _stdcall even_thread_cs(void *p)
{
for( int i = 0 ; i < MAX ; i++ )
{
EnterCriticalSection(&cs);
if( shared_value % 2 == 0 )
{
printf("\n%d", i);
}
LeaveCriticalSection(&cs);
}
return 0;
}
unsigned _stdcall odd_thread_cs(void *p)
{
for( int i = 0 ; i < MAX ; i++ )
{
EnterCriticalSection(&cs);
if( shared_value % 2 != 0 )
{
printf("\n%d", i);
}
LeaveCriticalSection(&cs);
}
return 0;
}
int main(int argc, char* argv[])
{
InitializeCriticalSection(&cs);
_beginthreadex(NULL, NULL, even_thread_cs, 0,0, 0);
_beginthreadex(NULL, NULL, odd_thread_cs, 0,0, 0);
getchar();
return 0;
}
Here, using shared variable shared_value, we are synchronizing the even_thread_cs and odd_thread_cs.
Note that sleep is not used.
来源:https://stackoverflow.com/questions/14641134/printing-odd-and-even-number-printing-alternately-using-threads-in-c