c++ 多线程交替打印(线程同步)三种方式。

1.线程同步的三种方式

原子操作、条件变量和信号量是并发编程中用于同步和互斥的几种机制。

1.原子操作

  • 原子操作是指不会被线程调度机制打断的操作,一旦开始执行,就会一直运行到结束,中间不会有任何上下文切换。原子操作通常用于实现对共享资源的无锁访问,例如,对一个计数器的自增操作。C++11引入了std::atomic模板类,用于支持原子类型和原子操作。

  • #include <atomic>
    std::atomic<int> counter(0);
    
    void incrementCounter() {
        ++counter;
    }
    

    更多内容(原子操作,thread,function,bind 等相关资料)和资料:可以参考:   C++ 11 (三)-CSDN博客

  • 2.条件变量

  • 条件变量是一种同步机制,允许线程等待某个条件的发生。它通常与互斥量一起使用,以确保在等待条件时对共享资源的访问是互斥的。条件变量的核心操作是waitnotify_onenotify_allwait操作会使线程进入等待状态,直到被notify_onenotify_all唤醒。

    示例代码:

  • #include <mutex>
    #include <condition_variable>
    
    std::mutex mtx;
    std::condition_variable cv;
    bool ready = false;
    
    void waitForSignal() {
        std::unique_lock<std::mutex> lck(mtx);
        cv.wait(lck, []{ return ready; });
        // 被唤醒后执行的操作
    }
    
    void sendSignal() {
        std::lock_guard<std::mutex> lck(mtx);
        ready = true;
        cv.notify_one();
    }
    

    3信号量

  • 信号量是一种用于控制同时访问共享资源的线程数量的同步机制。信号量有一个计数器,用于表示当前可用的资源数量。线程在访问资源前需要获取信号量,如果信号量的值大于0,则线程可以继续执行,并将信号量的值减1;如果信号量的值为0,则线程进入等待状态。C++中并没有内置的信号量类,但可以使用POSIX信号量或自定义实现。

    示例代码(使用POSIX信号量):

  • #include <semaphore.h>
    
    sem_t sem;
    
    void initSemaphore() {
        sem_init(&sem, 0, 1); // 初始值为1,表示有一个资源可用
    }
    
    void waitSemaphore() {
        sem_wait(&sem);
        // 访问资源
        sem_post(&sem);
    }
    

2.题目相关

参考leetcode 1115

. - 力扣(LeetCode)

题目描述:

给你一个类:

class FooBar {
private:
    int n;

public:
    FooBar(int n) {
        this->n = n;
    }

    void foo(function<void()> printFoo) {
        
        for (int i = 0; i < n; i++) {
            
        	// printFoo() outputs "foo". Do not change or remove this line.
        	printFoo();
        }
    }

    void bar(function<void()> printBar) {
        
        for (int i = 0; i < n; i++) {
            
        	// printBar() outputs "bar". Do not change or remove this line.
        	printBar();
        }
    }
};

两个不同的线程将会共用一个 FooBar 实例:

线程 A 将会调用 foo() 方法,而

线程 B 将会调用 bar() 方法

请设计修改程序,以确保 "foobar" 被输出 n 次。

示例 1:

输入:n = 1

输出:"foobar"

解释:这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法,"foobar" 将被输出一次。

示例 2:

输入:n = 2

输出:"foobarfoobar"

解释:"foobar" 将被输出两次。

*/

解答一:使用原子量。

#include<iosteam>
#include<mutex>
#include<thread>
#include<atomic>
class FooBar2{
  private:
    int n;
    atomic<bool> flag;
  public:
    void printFoo(){
    cout<<"Foo";
  }

  void printBar(){
    cout<<"Bar";
  }
  FooBar2(int n){
    this->n = n;
    flag = false;
  } 

  void foo(function<void()> printFoo){
    for(int i = 0;i<n;i++){
      while(flag){
        this_thread::yield();
      }
      printFoo();
      flag = true;
    }
  }

  void bar(function<void()> printBar){
    for(int i = 0;i<n;i++){
      while(!flag){
        this_thread::yield();
      }
      printBar();
      flag = false;
    }
  }


//编译的时候需要加上-l pthread.
};



int main()
{
    int n=5;
    FooBar2 fb2(n);

    thread t1(&FooBar2::foo,&fb2,bind(&FooBar2::printBar,&fb2));
    thread t2(&FooBar2::bar,&fb2,bind(&FooBar2::printFoo,&fb2));

    t1.join();
    t2.join();
  return 0;
}
 

解答二:使用条件变量+互斥锁

class FooBar
{
private:
  int n;
  mutex mtx;
  bool flag = false;
  condition_variable cv;

public:
  FooBar(int n)
  {
    this->n = n;
  }
  void printFoo()
  {
    cout << "Foo";
  }
  void printBar()
  {
    cout << "Bar";
  }

  void foo(function<void()> printFoo)
  {

    for (int i = 0; i < n; i++)
    {
      unique_lock<mutex> lck(mtx);

      cv.wait(lck, [this]()
              { return !this->flag; });
 
      printFoo();
      flag = true;
      cv.notify_one();
    }
  }

  void bar(function<void()> printBar)
  {

    for (int i = 0; i < n; i++)
    {
      unique_lock<mutex> lck(mtx);
      cv.wait(lck, [this]()
              { return flag; });
      printBar();
      flag = false;
      cv.notify_one();
    }
  }
};

解答三:使用条件变量。

需要在linux 下进行,同时编译的时候需要指明线程库

即g++ name.cpp -o name -l pthread. 才可以进行使用。


#include<semaphore.h>
class FooBar
{
private:
  int n;
  sem_t foo_Done;
  sem_t bar_Done;
 
public:
  FooBar(int n)
  {
    this->n = n;
    sem_init(&foo_Done, 0, 0);
    sem_init(&bar_Done, 0, 1);
  }
  void printFoo()
  {
    cout << "Foo";
  }
  void printBar()
  {
    cout << "Bar";
  }

  void foo(function<void()> printFoo)
  {

    for (int i = 0; i < n; i++)
    {
      sem_wait(&bar_Done);
 
      printFoo();
      sem_post(&foo_Done);
    }
  }

  void bar(function<void()> printBar)
  {

    for (int i = 0; i < n; i++)
    {

      sem_wait(&foo_Done);
      printBar();
      sem_post(&bar_Done);
    }
  }
};

测试代码同解答一main()函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值