循环控制 - `break` 和 `continue`

循环控制 - `break` 和 `continue`

在 C++ 中,breakcontinue 是用于控制循环执行流的两个重要语句。它们帮助我们根据特定条件来决定是否提前退出循环或跳过当前循环的某次执行。

break 语句

break 语句用于立即退出循环,其后面的所有代码都不会执行。常用于当满足某种条件时中断循环。

使用场景

  1. 找到特定元素时退出循环
  2. 用户输入为特定值时结束程序

语法

1
break;

示例代码

以下是一个使用 break 语句的示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main() {
for (int i = 0; i < 10; i++) {
if (i == 5) {
std::cout << "找到 5,退出循环。" << std::endl;
break; // 一旦 i 等于 5,就退出循环
}
std::cout << "当前数字: " << i << std::endl;
}
return 0;
}

运行结果

1
2
3
4
5
6
当前数字: 0
当前数字: 1
当前数字: 2
当前数字: 3
当前数字: 4
找到 5,退出循环。

在这个示例中,当 i 等于 5 时,break 语句会被执行,从而中断了循环。

continue 语句

continue 语句用于跳过当前循环的剩余代码,并立即开始下一轮循环。这非常适合于当某个条件被满足时我们希望忽略此轮的处理。

使用场景

  1. 过滤特定条件的元素
  2. 跳过错误数据的处理

语法

1
continue;

示例代码

以下是一个使用 continue 语句的示例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int main() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
std::cout << "跳过偶数: " << i << std::endl;
continue; // 如果是偶数,跳过本次循环
}
std::cout << "处理奇数: " << i << std::endl;
}
return 0;
}

运行结果

1
2
3
4
5
6
7
8
9
10
跳过偶数: 0
处理奇数: 1
跳过偶数: 2
处理奇数: 3
跳过偶数: 4
处理奇数: 5
跳过偶数: 6
处理奇数: 7
跳过偶数: 8
处理奇数: 9

在这个示例中,continue 语句确保了遇到偶数时,只打印“跳过偶数”的消息,跳过了处理奇数的部分。

总结

  • break 语句用于立即退出循环。
  • continue 语句用于跳过当前循环的剩余代码,进入下一个迭代。
  • 这两个控制语句可以使我们的循环更灵活,更符合程序逻辑。

通过充分理解和使用 breakcontinue,你可以更有效地控制 C++ 程序中的循环结构。希望这些示例能帮助你更好地理解它们的用法!

18 C++ 线程同步与锁机制

18 C++ 线程同步与锁机制

在多线程编程中,线程之间的同步是非常重要的,以确保共享资源的安全访问。C++11引入了一套新的线程库,提供了多种工具来实现线程同步,包括锁机制、条件变量等。

1. 线程同步的必要性

多线程程序中,多个线程可能会同时访问同一共享资源,例如一个变量、数组或数据结构。如果没有正确的同步机制,将会导致数据竞争和不一致性现象。

1.1 数据竞争

数据竞争(Data Race)发生在两个或多个线程访问同一共享变量,其中至少一个线程在写入该变量,而没有适当的同步机制。这可能导致程序输出不可预测的结果。

1.2 解决数据竞争

通过同步机制,确保同一时间只有一个线程能够访问共享资源,从而解决数据竞争问题。

2. 锁机制

C++提供了几种锁机制来实现线程同步,最常用的是std::mutex

2.1 std::mutex

std::mutex 是一个互斥量,能够确保同一时刻只有一个线程能够访问特定的资源。

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 创建一个互斥量
int shared_data = 0;

void increment() {
for (int i = 0; i < 100000; ++i) {
mtx.lock(); // 上锁
++shared_data; // 修改共享数据
mtx.unlock(); // 解锁
}
}

int main() {
std::thread t1(increment);
std::thread t2(increment);

t1.join();
t2.join();

std::cout << "Final value of shared_data: " << shared_data << std::endl;
return 0;
}

在上面的代码中,两个线程都在对shared_data变量进行递增操作。通过mtx.lock()mtx.unlock()来确保同一时刻只有一个线程能修改shared_data

2.2 std::lock_guard

std::lock_guard是一个RAII风格的锁,能够自动管理锁的生命周期。它在构造时自动加锁,在析构时自动解锁。

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 创建一个互斥量
int shared_data = 0;

void increment() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁
++shared_data; // 修改共享数据
// lock_guard会在此作用域结束时自动解锁
}
}

int main() {
std::thread t1(increment);
std::thread t2(increment);

t1.join();
t2.join();

std::cout << "Final value of shared_data: " << shared_data << std::endl;
return 0;
}

使用std::lock_guard可以减少手动管理锁的复杂度,避免死锁的风险。

3. 条件变量

当线程需要等待某个条件满足时,std::condition_variable可以用来进行线程间的通信。

使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void wait_for_ready() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; }); // 等待直到ready变为true
std::cout << "Thread proceeding after being notified." << std::endl;
}

void go() {
std::unique_lock<std::mutex> lock(mtx);
ready = true; // 改变条件
cv.notify_one(); // 通知一个等待的线程
}

int main() {
std::thread t1(wait_for_ready);
std::thread t2(go);

t1.join();
t2.join();

return 0;
}

在此案例中,wait_for_ready函数会等待ready变为true,而go函数会改变这个条件并通知等待线程。

4. 总结

在C++中,线程同步是一个关键的主题,通过使用锁机制,例如std::mutexstd::lock_guard,可以确保数据的一致性和完整性。同时,std::condition_variable提供了线程间的高效通信手段。这些工具的正确使用能够显著提高多线程程序的安全性和性能。通过避免数据竞争和使用适当的同步手段,多线程编程将变得更为可靠。

函数的定义与调用

函数的定义与调用

在 C++ 中,函数是代码的一个基本结构,它允许我们将重复的任务封装成一个可重用的模块。接下来,我们将详细讨论函数的定义与调用。

1. 函数的基本概念

函数是一组执行特定任务的语句。通过调用函数,可以避免重复代码,并提高代码的可读性和可维护性。函数可以接受参数,并可能返回一个值。

2. 函数的定义

在 C++ 中,函数的定义包括以下几个部分:

  • 返回类型(Return Type)
  • 函数名称(Function Name)
  • 参数列表(Parameter List)
  • 函数体(Function Body)

2.1 函数定义的语法

1
2
3
4
5
返回类型 函数名(参数类型 参数名1, 参数类型 参数名2, ...) {
// 函数体
// 执行代码
return 返回值; // 可选
}

2.2 示例:定义一个简单的函数

以下是一个简单的函数定义的例子,该函数用于计算两个整数的和。

1
2
3
4
int add(int a, int b) {
int sum = a + b;
return sum; // 返回两个数的和
}

在这个示例中:

  • int 是返回类型,表示函数返回一个整数。
  • add 是函数名称。
  • (int a, int b) 是参数列表,接受两个整数作为参数。
  • {} 是函数体,包含了计算和返回结果的代码。

3. 函数的调用

函数定义后,可以通过函数调用来执行它。在 C++ 中,函数的调用遵循以下语法:

1
函数名(参数1, 参数2, ...);

3.1 示例:调用定义的函数

继续使用上面的 add 函数,我们可以在 main 函数中调用它:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;

int add(int a, int b) {
return a + b;
}

int main() {
int result = add(5, 3); // 准备调用 add 函数
cout << "5 + 3 = " << result << endl; // 输出结果
return 0;
}

在这个例子中:

  • 我们在 main 函数中调用 add 函数,传递了 53 作为参数。
  • add(5, 3) 返回的值被存储在 result 变量中。
  • 使用 cout 输出结果。

4. 函数的注意事项

  • 函数名必须是唯一的,不能与同一作用域内的其他函数名重复。
  • 参数的类型和顺序是重要的,在调用时必须保持一致。
  • 如果函数定义有返回类型,则必须在函数体中的某处使用 return 语句返回一个值。
  • 如果函数不返回值,返回类型应为 void,例如:
1
2
3
void printMessage() {
cout << "Hello, World!" << endl;
}

以上就是关于 C++ 中函数的定义与调用的基本介绍。掌握这些概念对于进一步学习 C++ 程序设计至关重要。