笔记9.18
线程之间的通信是指在多线程程序中,不同线程之间如何交换数据或协调工作。这种通信对于实现复杂的并发程序是至关重要的。以下是几种常见的线程间通信方式:
-
共享内存:
- 这是最直接的方式,多个线程通过读写同一块内存区域(如全局变量)来交换信息。但是这种方式需要特别注意同步问题,比如使用互斥锁(Mutex)、信号量(Semaphore)等机制来防止数据竞争和死锁。
-
消息传递:
- 在某些编程环境中,线程可以通过发送消息来进行通信。每个线程都有自己的私有队列,消息被放入接收者的队列中等待处理。这种方式可以减少线程间的耦合度,并且易于实现非阻塞操作。
-
管道(Pipes):
- 管道是一种进程间通信方式,也可以用于线程间通信。一个线程写入管道的数据可以被另一个线程读取。管道分为匿名管道和命名管道两种类型,前者只能用于具有亲缘关系的进程间通信,后者则不受此限制。
-
信号(Signals):
- 信号是一种异步通知机制,当某个特定事件发生时,系统会向进程发送一个信号。虽然信号主要用于进程间通信,但在某些情况下也可以用作线程间通信的一种手段。
-
条件变量(Condition Variables):
- 条件变量通常与互斥锁一起使用,允许一个或多个线程等待直到某个特定条件为真。这在实现生产者-消费者模式等场景中非常有用。
-
事件(Events):
- 事件对象提供了一种简单的同步机制,其中一个线程设置事件的状态,而其他线程可以等待该状态的变化。这在Windows操作系统中尤其常见。
-
屏障(Barriers):
- 屏障是一种同步点,所有到达这个点的线程都会被阻塞,直到所有参与的线程都到达了这个点。这是实现多线程协作完成任务的一种有效方法。
-
static 和 const 是 C/C++ 中常用的两个关键字,它们各自有不同的用途和特性。下面详细解释两者的区别:
const
const 关键字用于声明一个常量,表示该变量的值在初始化后不能被修改。const 可以应用于各种数据类型,包括基本数据类型、指针、函数参数等。特点:
不可变性:一旦初始化,const 变量的值不能被改变。
存储位置:const 变量通常存储在只读内存区域,编译器会对其进行优化。
作用域:const 变量的作用域取决于其声明的位置。可以在局部作用域(函数内部)或全局作用域声明。
示例:const int a = 10; // 全局常量 void func() { const int b = 20; // 局部常量 }
static
static 关键字用于控制变量的存储方式和作用域。它主要有以下几个用途:1. 静态局部变量:
在函数内部声明的 static 变量在函数调用之间保持其值。
初始化:静态局部变量只在第一次进入函数时初始化一次。
生命周期:静态局部变量的生命周期贯穿整个程序运行期。
作用域:静态局部变量的作用域仍然限于声明它的函数内部。
示例:void func() { static int count = 0; count++; std::cout << "Count: " << count << std::endl; }
2. 静态全局变量:
在文件作用域内声明的 static 变量仅在声明它的文件内可见,不能被其他文件访问。
初始化:静态全局变量在程序启动时初始化。
生命周期:静态全局变量的生命周期贯穿整个程序运行期。
作用域:静态全局变量的作用域限于声明它的文件。
示例:// file1.cpp static int globalVar = 10; void func1() { std::cout << "globalVar: " << globalVar << std::endl; } // file2.cpp // int globalVar; // 这里无法访问 file1.cpp 中的 globalVar
3. 静态成员变量:
在类中声明的 static 成员变量属于类本身,而不是类的任何特定对象。
初始化:静态成员变量必须在类外部初始化。
生命周期:静态成员变量的生命周期贯穿整个程序运行期。
作用域:静态成员变量的作用域限于声明它的类。
示例:class MyClass { public: static int staticVar; }; int MyClass::staticVar = 0; // 静态成员变量的初始化 void func() { MyClass::staticVar++; std::cout << "StaticVar: " << MyClass::staticVar << std::endl; }
总结
const:用于声明常量,表示该变量的值在初始化后不能被修改。
static:用于控制变量的存储方式和作用域,可以用于局部变量、全局变量和类成员变量。
两者在用途和特性上有明显的区别,但在实际编程中经常结合使用,以实现更复杂的功能和更好的代码组织。