让两个线程顺序执行

并发编程:线程间的同步与等待
本文探讨了Java中使用线程实现并发编程的技巧,通过创建两个线程并利用`synchronized`关键字和`wait`/`notifyAll`方法进行线程间的同步与等待操作,展示了如何有效地管理多线程环境中的资源竞争问题。
 1 public class ThreadJoiner {
 2     public static void main(String[] args) {
 3         Object lock = new Object();
 4            
 5         Thread starterThread = new Thread(new StarterThread(lock));
 6         Thread enderThread = new Thread(new EnderThread(lock));
 7        
 8         starterThread.start();
 9         enderThread.start();
10     }
11 }
12 class StarterThread implements Runnable {
13 
14     private Object lock = null;
15    
16     public StarterThread(Object lock) {
17         this.lock = lock;
18     }
19 
20     public void run() {
21         System.out.println("start..");
22        
23         for(int i =0; i<10; i++){
24             System.out.println("start:"+i);
25         } 
26         synchronized(lock){
27             lock.notifyAll();
28         }
29     }
30 }
31 class EnderThread implements Runnable {
32     private Object lock = null;
33     public EnderThread(Object lock) {
34         this.lock = lock;
35     }
36 
37     public void run() {
38         synchronized(lock){
39             try {
40                 lock.wait();
41             } catch (InterruptedException e) {
42                 e.printStackTrace();
43             }
44         }
45         System.out.println("end..");
46         for(int i =0; i<10; i++){
47             System.out.println("end:"+i);
48         }  
49     }
50 }
51 /*
52 start..
53 start:0
54 start:1
55 start:2
56 start:3
57 start:4
58 start:5
59 start:6
60 start:7
61 start:8
62 start:9
63 end..
64 end:0
65 end:1
66 end:2
67 end:3
68 end:4
69 end:5
70 end:6
71 end:7
72 end:8
73 end:9
74 */

 

转载于:https://www.cnblogs.com/wanghui390/p/3443572.html

<think>我们被要求用C++实现两个线程顺序执行,即一个线程执行完后另一个再执行。参考引用中提供了Java使用join()方法的例子,C++中也有类似的机制。在C++11中,我们可以使用std::thread的join()方法来实现。join()方法会阻塞当前线程,直到被调用的线程执行完毕。具体步骤:1.创建两个线程:thread1和thread2。2.在启动thread2之前,我们可以在主线程中调用thread1.join(),这样主线程会等待thread1完成后再启动thread2。或者,我们也可以在线程函数内部使用join,但更常见的做法是在主线程中控制。另一种方式:如果我们希望thread2在thread1之后执行,那么可以在thread2的线程函数中先调用thread1.join()(注意需要将thread1作为可访问对象),但这样需要thread1已经启动,并且thread2能够访问到thread1对象。通常更简单的方式是在主线程中按顺序join。然而,根据引用的思路,我们可以这样:-先启动thread1,然后立即在主线程中jointhread1,这样主线程就会等待thread1结束。-然后再启动thread2,并在主线程中jointhread2。但是,如果我们希望两个线程都是异步启动,但thread2必须等待thread1完成,那么可以在thread2的线程函数中等待thread1完成(通过join)。但要注意,thread1对象必须在thread2的线程函数中可见,且要保证thread1已经启动(否则join可能出错)。下面我们给出两种实现方式:方式一:在主线程顺序启动并等待(先启动thread1,等待完成后再启动thread2)方式二:同时启动两个线程,但在thread2中等待thread1完成(使用join)注意:方式二需要将thread1对象传递给thread2,并且要确保thread1在thread2尝试join之前已经启动。由于线程启动后可能立即被调度,也可能稍后调度,所以我们需要确保thread1先启动,但为了安全,我们可以在thread2中判断thread1是否可join(这里我们通过在主线程中先启动thread1,再启动thread2,然后在thread2中jointhread1)。然而,更推荐方式一,因为它简单且不易出错。下面我们分别用两种方式写代码示例。方式一:```cpp#include<iostream>#include<thread>voidtask1(){//执行一些任务std::cout<<"Thread1isrunning."<<std::endl;}voidtask2(){//执行一些任务std::cout<<"Thread2isrunning."<<std::endl;}intmain(){//创建线程对象std::threadt1(task1);//等待t1完成t1.join();//现在启动t2std::threadt2(task2);t2.join();return0;}```方式二:将thread1传递给thread2,并在task2中等待thread1完成。注意,我们需要将thread1对象以引用的方式传递给task2(注意线程对象只能被移动,不能复制,所以我们需要使用std::ref或者指针,但这里我们使用lambda捕获引用,但要注意线程对象的生命周期)。注意:方式二需要小心,因为如果thread1在thread2开始执行之前就已经结束,那么thread1.join()会立即返回,没有问题。但是,如果thread1还没有启动(这种情况不会发生,因为我们在主线程中先启动了thread1)或者已经启动,join是安全的。方式二代码示例:```cpp#include<iostream>#include<thread>voidtask1(){std::cout<<"Thread1isrunning."<<std::endl;}voidtask2(std::thread&t){//等待传入的线程t完成if(t.joinable()){t.join();}std::cout<<"Thread2isrunning."<<std::endl;}intmain(){std::threadt1(task1);//注意:这里我们使用std::ref将t1的引用传递给task2,但是task2的参数类型是std::thread&,而std::thread的拷贝构造函数被删除,所以我们需要使用引用传递。//但是,我们也可以使用lambda表达式来捕获t1的引用。std::threadt2([&](){if(t1.joinable()){t1.join();}task2();//或者直接把任务写在这里});//注意:这里我们只需要joint2,因为t1已经在t2中被join了。但是,我们仍然需要确保t1和t2在主线程结束前被join(或者detach)。由于t2中已经join了t1,那么t1在主线程中就不需要再join了,否则会二次join导致程序崩溃。//所以,我们只joint2。t2.join();return0;}```但是方式二需要注意:-在t2中,我们通过lambda捕获了t1的引用,这要求t1的生命周期要长于t2的执行时间。由于我们在主线程中先创建t1,然后创建t2,最后等待t2结束,所以t1在t2执行期间是有效的。-另外,在t2中调用t1.join()后,t1就变为不可joinable了,所以我们在主线程中不能再对t1调用join()。所以,方式二虽然可以同时启动两个线程(但实际上t2会等待t1完成),但代码复杂度较高,且容易出错。因此,对于两个线程顺序执行的情况,方式一更简单直接。总结:推荐使用方式一,即主线程中先启动第一个线程并等待其完成,然后启动第二个线程并等待。但是,如果问题要求两个线程都启动,然后第二个线程等待第一个线程完成,那么方式二也是一种选择。根据问题,我们只需要两个线程顺序执行,所以方式一即可满足。另外,C++11还提供了其他同步机制,比如条件变量、互斥锁等,但这里用join是最简单的。因此,我们给出方式一的代码作为主要答案。注意:如果线程需要传递参数,可以在创建线程时传递。最后,生成相关问题。</think>### C++中实现两个线程顺序执行的方法 在C++11及以上版本中,可以使用`std::thread`的`join()`方法实现线程顺序执行。`join()`会阻塞当前线程,直到目标线程执行完毕。以下是两种实现方式: #### 方法1:在主线程中控制顺序(推荐) ```cpp #include <iostream> #include <thread> void task1() { std::cout << "线程1执行" << std::endl; } void task2() { std::cout << "线程2执行" << std::endl; } int main() { // 创建线程对象 std::thread t1(task1); // 阻塞主线程,等待t1完成 t1.join(); // 启动t2(此时t1已结束) std::thread t2(task2); t2.join(); return 0; } ``` **输出**: ``` 线程1执行 线程2执行 ``` #### 方法2:在线程内部控制顺序 ```cpp #include <iostream> #include <thread> void task1() { std::cout << "线程1执行" << std::endl; } void task2(std::thread& prev_thread) { if (prev_thread.joinable()) { prev_thread.join(); // 等待传入线程结束 } std::cout << "线程2执行" << std::endl; } int main() { std::thread t1(task1); std::thread t2([&] { task2(t1); }); // Lambda捕获t1的引用 t2.join(); // 只需等待t2完成(t1已在t2内部join) return 0; } ``` #### 关键点说明: 1. **`join()`的作用**: 阻塞当前线程直到目标线程结束执行,通过控制`join()`的调用位置实现顺序控制[^1][^2]。 2. **线程生命周期管理**: - 线程对象在析构前必须调用`join()`或`detach()` - 重复调用`join()`会导致`std::system_error`异常 - 检查线程状态用`joinable()` 3. **C++11线程特性**: - 需包含头文件`<thread>` - 编译时添加`-pthread`标志(GCC/Clang) - 线程函数支持Lambda表达式、函数指针、可调用对象[^4] > **应用场景**:日志顺序写入、流水线任务处理、多阶段计算等需要严格顺序执行的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值