5

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.

4

17 回答 17

7

使用条件变量

#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;
}
于 2018-06-12T08:55:47.573 回答
3

使用条件变量的解决方案。

#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex oddevenMu;
condition_variable condVar;
int number = 1;

void printEvenOdd(bool isEven, int maxnubmer)
{
    unique_lock<mutex> ul(oddevenMu);
    while (number < maxnubmer)
    {
        condVar.wait(ul, [&]() {return number % 2 == isEven;});
        cout << number++ << " ";
        condVar.notify_all();
    }

}

int main(string args[])
{
    thread oddThread(printEvenOdd, false, 100);
    thread evenThread(printEvenOdd, true, 100);
    oddThread.join();
    evenThread.join();
    return 0;
}
于 2019-12-04T11:59:41.173 回答
1
 #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;
}
于 2014-09-18T16:50:08.163 回答
1

这是使用单一功能的简单解决方案。

#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;
}
于 2019-10-21T17:16:20.807 回答
1
    #include <iostream>
    #include <thread>
    #include <mutex> 
    using namespace std;

    std::mutex m;
    int count = 0;

    void printEven()
    {
        cout << "Entered Even\n" << endl;
        while(count <= 10)
        {
            m.lock();
            if(count%2 == 0)
                cout << count++ << " ";
             m.unlock();
        }
    }
    
    void printOdd()
    {
        cout << "Entered Odd" << endl;
        while(count < 10)
        {
             m.lock();
            if(count%2 == 1)
                cout << count++ << " ";
             m.unlock();
        }
    }

    int main()
    {
       std::thread t1(printOdd);
       std::thread t2(printEven);
       t1.join();
       t2.join();
        return 0;
    }
于 2021-05-27T07:21:56.367 回答
1

这是您可以参考的最简单的解决方案:

#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;
 }
于 2018-10-20T14:46:52.413 回答
0

首先,这两个函数应该至少包含一个循环,(除非你只想要一个数字)

一个更标准的解决方案(重新映射您的想法)是拥有一个包含互斥体的全局结构,以及两个条件变量(奇数和偶数)加上一个返回值,以及另一个打印条件。而不是使用 uique_lock 来处理同步。

在伪代码中:

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();
}

请注意,除了教学目的之外,此解决方案对于打印计数器值的简单循环没有增加任何价值,因为永远不会有真正的并发性。

还要注意(为了避免全局变量),您可以将所有内容包装到一个类中(使实际的 main 成为类方法)并在新 main 内的堆栈上实例化该类。

于 2013-02-01T07:43:59.373 回答
0

我不明白为什么要使用三个单独的线程来进行串行行为。但无论如何我都会回答:)

一种解决方案是使用修改后的生产者/消费者模式,在生产者和消费者之间设置优先队列。队列上的排序操作将取决于发布消息的整数值。消费者会查看队列中的一个元素并检查它是否是下一个预期元素。如果没有,它会休眠/等待。

一点代码:

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));
  }
}
于 2013-02-01T07:32:05.573 回答
0

解决方案基于 C++11 关键代码部分(又名mutex)。

这是工作代码,然后是解释。

在 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;
 }
}

IE:

线程奇数转到方法oddAndEven,起始编号为1,因此他是奇数。他是第一个获得锁的人mtx.lock()

同时,线程Even 也尝试获取锁,但线程奇数首先获得了它,因此线程Even等待。

回到线程奇数(有锁),他打印数字 1 并用 释放锁mtx.unlock()。此时,我们希望线程Even获取锁并打印 2,因此我们通过写入来通知线程Evenstd::this_thread::yield()。然后线程Even做同样的事情。

等等等等等等

于 2015-05-15T19:25:13.150 回答
0
#include <bits/stdc++.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

mutex m;
condition_variable cv;
unique_lock<mutex> lck(m);

void *printeven(void *arg)
{
    int *n = (int *)arg;
    while (*n <= 100)
    {
        cv.wait(lck);
        *n = *((int *)arg);
        cout << this_thread::get_id() << " : " << *n << endl;
        *n = *n + 1;
        cv.notify_one();
    }
    exit(0);
}

void *printodd(void *arg)
{
    int *n = (int *)arg;
    while (*n <= 100)
    {
        *n = *((int *)arg);
        cout << this_thread::get_id() << " : " << *n << endl;
        *n = *n + 1;
        cv.notify_one();
        cv.wait(lck);
    }
    exit(0);
}

int main()
{
    int num = 1;
    pthread_t p1 = 1;
    pthread_t p2 = 2;

    pthread_create(&p1, NULL, printodd, &num);
    pthread_create(&p2, NULL, printeven, &num);

    pthread_join(p1, NULL);
    pthread_join(p2, NULL);
    return 0;
}
于 2021-11-17T13:57:57.873 回答
0
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
std::mutex m;
std::condition_variable cv;
int counter =1;

void printEven()
{
    std::unique_lock<std::mutex> lk(m);
    while(1)
    {
        if(counter > 10)
            break;
        if(counter %2 != 0)
        {
            cv.wait (lk);
        }
        else
        {
            cout << "counter : " << counter << endl;
            counter++;
            //lk.unlock();
            cv.notify_one();
        }
    
    
    }
}


void printOdd()
{
    std::unique_lock<std::mutex> lk(m);
    
    while(1)
    {
        if(counter > 9)
        break;
        if(counter %2 == 0)
        {
            cv.wait (lk);
        }
        else
        {
            cout << "counter : " << counter << endl;
            counter++;
            //lk.unlock();
            cv.notify_one();
        }
    
    
    }
}

int main()
{
    std::thread t1(printEven);
    std::thread t2(printOdd);
    t1.join();
    t2.join();
    cout << "Main Ends" << endl;
}
于 2021-07-14T15:44:03.283 回答
0
#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;
}
于 2019-09-07T19:01:55.433 回答
0

我已经使用匿名 func (lambda) 来执行此操作,并使用了 cond 变量和互斥锁。

#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>

using namespace std; 

int main() {
    int count = 1;
    mutex mtx;
    condition_variable condition;
    const int ITERATIONS = 20; // iterations

    //prints odd numbers
    thread t1([&]() {
        while (count < ITERATIONS)
        {
            unique_lock <mutex> lock(mtx);
            condition.wait(lock, [&]() {
                return count % 2 != 0;
                });

            cout << "thread1 prints: " << count << endl;
            count++;
            lock.unlock();
            condition.notify_all();
        }
    });
    
    thread t2([&]
        {
            while (count < ITERATIONS)
            {
                unique_lock <mutex> lock(mtx);
                condition.wait(lock, [&]() {
                    return count % 2 == 0;
                    });
                cout << "thread2 prints: " << count << endl;
                count++;
                lock.unlock();
                condition.notify_all();
            }
        });

    t1.join();
    t2.join();
 }
于 2021-08-27T16:13:16.953 回答
0
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable even_to_odd;
std::condition_variable odd_to_even;
unsigned int count = 1;
constexpr int MAX_COUNT = 20;

void even(int n) {
    for (int i = n; i <= MAX_COUNT; i++) {
        std::unique_lock<std::mutex> lock(mtx);
        if (i %2 == 0) {
            odd_to_even.wait(lock);
            std::cout << "Even: " << i << std::endl;
            even_to_odd.notify_one();
        }
    }
}

void odd(int n) {
    for (int i = n; i <= MAX_COUNT; i++) {
        std::unique_lock<std::mutex> lock(mtx);
        if (i == 1) {
            std::cout << "Odd : " << i << std::endl;
            odd_to_even.notify_one();
        }
        else if (i % 2 != 0) {
            even_to_odd.wait(lock);
            std::cout << "Odd : " << i << std::endl;
            odd_to_even.notify_one();
        }
    }
}

int main() {
    std::thread thread1(even,count);
    std::thread thread2(odd,count);

    thread1.join();
    thread2.join();
    return 0;
}
于 2021-11-24T08:33:11.913 回答
0
#include "threadFunc.hpp"
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

mutex t1;
condition_variable cond;


int number = 11;
int count = 0;

void printEven()
{
    while(1)
    {
        unique_lock<mutex> ul(t1);
        if(count< number)
        {
            if(count % 2 != 0)
            {
                cond.wait(ul);
            }

            cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
            count++;
        }
        if(count > number)
            break;

        ul.unlock();
        cond.notify_all();
    }

}

void printOdd()
{
    while(1)
    {
        unique_lock<mutex> ul(t1);
        if(count< number)
        {
            if(count % 2 == 0)
            {
                cond.wait(ul);
            }

            cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
            count++;
        }
        if(count > number)
            break;

        ul.unlock();
        cond.notify_all();
    }

}
于 2021-11-13T12:39:32.410 回答
0

此代码将起作用。我已经在 Visual Studio 2017 上对其进行了测试

#include "stdafx.h"
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
mutex m;
condition_variable cv;
int num = 1;


void oddThread() {​​​​​​​
    
    for (; num < 10;) {​​​​​​​
        unique_lock<mutex> lg(m);
        cv.wait(lg, [] {​​​​​​​return (num % 2 ==1); }​​​​​​​);
        cout << "From odd Thread " << num << endl;
        num++;
        lg.unlock();
        cv.notify_one();
    }​​​​​​​
}​​​​​​​
void evenThread() {​​​​​​​
    for (; num < 100;) {​​​​​​​
        unique_lock<mutex> lg(m);
        cv.wait(lg, [] {​​​​​​​return (num % 2 == 0); }​​​​​​​);
        cout << "From even Thread " << num << endl;
        num++;
        lg.unlock();
        cv.notify_one();
    }​​​​​​​
}​​​​​​​


int main() {​​​​​​​
    
    thread t1{​​​​​​​ oddThread}​​​​​​​; //odd function thread
    thread t2{​​​​​​​ evenThread}​​​​​​​;
    t1.join();
    t2.join();
    cin.get();
    return 0;
}​​​​​​​

输出

从奇数线程:1 从偶数线程:2 从奇数线程:3 从偶数线程:4 从奇数线程:5 从偶数线程:6 从奇数线程:7 从偶数线程:8 从奇数线程:9 从偶数线程:10

于 2021-06-22T15:42:46.423 回答
-2

请参阅下面的工作代码(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;
}

在这里,使用共享变量shared_value,我们正在同步even_thread_csodd_thread_cs。请注意,不使用睡眠。

于 2013-04-29T06:10:42.820 回答