1114. 按序打印

我们提供了一个类:

public class Foo {
  public void one() { print("one"); }
  public void two() { print("two"); }
  public void three() { print("three"); }
}
三个不同的线程将会共用一个 Foo 实例。

线程 A 将会调用 one() 方法
线程 B 将会调用 two() 方法
线程 C 将会调用 three() 方法
请设计修改程序,以确保 two() 方法在 one() 方法之后被执行,three() 方法在 two() 方法之后被执行。

 

示例 1:

输入: [1,2,3]
输出: "onetwothree"
解释: 
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
正确的输出是 "onetwothree"。
示例 2:

输入: [1,3,2]
输出: "onetwothree"
解释: 
输入 [1,3,2] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 three() 方法,线程 C 将会调用 two() 方法。
正确的输出是 "onetwothree"。
 

注意:

尽管输入中的数字似乎暗示了顺序,但是我们并不保证线程在操作系统中的调度顺序。

你看到的输入格式主要是为了确保测试的全面性。

方法一:

使用全局变量来控制状态,但是需要声明为volatile,

 volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统,硬件或者其他线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

 volatile 关键字发挥了它的作用。其实不只是“内嵌汇编操纵栈”这种方式属于编译无法识别的变量改变,另外更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程 visible。一般说来,volatile用在如下的几个地方: 
1) 中断服务程序中修改的供其它程序检测的变量需要加volatile; 
2) 多任务环境下各任务间共享的标志应该加volatile; 
3) 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;

 

注意:(1) 可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。

          (2) 除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。
              (3) C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来获得对类型接口的完全访问。此外,volatile向const一样会从类传递到它的成员。

有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值

class Foo {
public:
    volatile int flag1=0;//volatile说明一种易变的变量
    volatile int flag2=0;
    Foo() {

    }
    void first(function printFirst) {
        // printFirst() outputs "first". Do not change or remove this line.
        printFirst();
        flag1++;
    }

    void second(function printSecond) {
        while(!flag1)
            ;
        
        // printSecond() outputs "second". Do not change or remove this line.
        printSecond();
        flag2++;
        flag1--;
    }

    void third(function printThird) {
        while(!flag2)
            ;
        // printThird() outputs "third". Do not change or remove this line.
        printThird();
        flag2--;
    }
};

 

方法2:

使用互斥量

class Foo {
public:
    mutex mux1;
    mutex mux2;
    Foo() {
        mux1.lock();
        mux2.lock();
    }
    void first(function printFirst) {
        // printFirst() outputs "first". Do not change or remove this line.
        printFirst();
        mux1.unlock();
    }

    void second(function printSecond) {
        //mux1.lock();
        lock_guard lg(mux1);    // 尝试锁上锁1,成功继续,否则等待
        // printSecond() outputs "second". Do not change or remove this line.
        printSecond();
        mux2.unlock();
        
    }

    void third(function printThird) {
        lock_guard lg(mux2);    // 尝试锁上锁1,成功继续,否则等待
        lock_guard lg1(mux1);    // 尝试锁上锁1,成功继续,否则等待
        //mux2.lock();
        // printThird() outputs "third". Do not change or remove this line.
        printThird();
        
    }
};

 

你可能感兴趣的:(多线程,Leetcode,C++)