网站描述案例,郑州it渠道网,网站开发的微端,东莞电商网站公司目录
一、什么是菱形继承#xff1f;
1.1.菱形继承的示例:
1.2.菱形继承的问题#xff1a;
1.3.解决菱形继承问题#xff1a;
二、C中的多线程同步机制#xff1f;
2.1.互斥锁#xff08;Mutex#xff09;:
2.2.递归互斥锁#xff08;Recursive Mutex#xff09…目录
一、什么是菱形继承
1.1.菱形继承的示例:
1.2.菱形继承的问题
1.3.解决菱形继承问题
二、C中的多线程同步机制
2.1.互斥锁Mutex:
2.2.递归互斥锁Recursive Mutex
2.3.读写锁Read-Write Lock:
2.4.条件变量Condition Variable:
2.5.原子操作Atomic Operations:
2.6.屏障Barrier:
2.7.信号量Semaphore:
2.8.纤程Fiber:
三、如何在c中创建和管理线程
3.1.包含必要的头文件:
3.2.创建线程:
3.3.等待线程结束:
3.4.分离线程:
3.5.使用线程局部存储:
3.6.线程同步:
3.7.线程同步:
3.8.线程同步:
3.9.使用 C20 协程:
总结 前言
在现代软件开发中多线程编程和继承结构的合理设计是提高程序性能和代码复用性的关键。C 作为一种功能强大的编程语言提供了丰富的特性来支持多线程编程和复杂的继承模式。本文档将详细介绍 C 中的菱形继承问题、多线程同步机制以及如何在 C 中创建和管理线程。 一、什么是菱形继承
在 C 中菱形继承Diamond Inheritance是指一个类称为派生类继承两个或多个基类而这些基类又有一个共同的基类。这种继承结构在类图上呈现出菱形因此得名。菱形继承在 C 中特别常见因为它允许多重继承这是 C 与其他面向对象语言如 Java 或 C#的一个重要区别。
1.1.菱形继承的示例:
class Base {
public:void show() { cout Base show endl; }
};class Derived1 : public Base {
public:void show() { cout Derived1 show endl; }
};class Derived2 : public Base {
public:void show() { cout Derived2 show endl; }
};class Diamond : public Derived1, public Derived2 {
public:void show() { cout Diamond show endl; }
};
在这个例子中Diamond 类继承自 Derived1 和 Derived2而这两个类又都继承自 Base 类。这就形成了一个菱形继承结构。
1.2.菱形继承的问题
菱形继承的主要问题是多重继承可能导致的二义性和资源浪费。在上述例子中Diamond 类会从 Derived1 和 Derived2 继承两个 Base 类的实例这可能导致以下问题 二义性如果 Diamond 类需要访问 Base 类的成员编译器可能会不确定应该使用哪个 Base 类的实例。 资源浪费每个 Derived1 和 Derived2 实例都有自己的 Base 实例这可能导致不必要的内存使用。
#include iostream
#include vector
#include algorithmint main() {std::vectorint nums {1, 2, 3, 4, 5};// 使用 lambda 表达式对向量进行排序std::sort(nums.begin(), nums.end(), [](int a, int b) {return a b; // 降序排序});// 使用 lambda 表达式打印向量中的元素std::for_each(nums.begin(), nums.end(), [](int n) {std::cout n ;});return 0;
}
1.3.解决菱形继承问题
C 提供了几种方法来解决菱形继承的问题 虚继承Virtual Inheritance通过使用虚继承可以确保 Base 类只有一个实例即使它被多个基类继承。这可以通过在继承列表中使用 virtual 关键字来实现。使用虚继承后Diamond 类将只有一个 Base 类的实例。 class Base {
public:void show() { cout Base show endl; }
};class Derived1 : virtual public Base {
// ...
};class Derived2 : virtual public Base {
// ...
};class Diamond : public Derived1, public Derived2 {
// ...
}; 接口继承在某些情况下可以通过将共同的基类定义为接口纯虚函数类来避免菱形继承的问题。 重新设计类结构有时重新设计类的结构可以避免菱形继承例如通过使用组合而不是继承。 二、C中的多线程同步机制
在 C 中多线程同步是确保多个线程在访问共享资源时能够正确、高效地协调工作的一种机制。C11 标准引入了多线程支持提供了一系列的同步工具包括互斥锁mutexes、条件变量condition variables、原子操作atomic operations等。以下是一些常用的多线程同步机制
2.1.互斥锁Mutex:
互斥锁用于保护临界区确保同一时间只有一个线程可以访问共享资源。在 C 中可以使用 std::mutex 来实现互斥锁。
#include mutex
#include threadstd::mutex mtx;
int shared_data 0;void increment() {mtx.lock();shared_data;mtx.unlock();
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}
2.2.递归互斥锁Recursive Mutex
递归互斥锁允许同一个线程多次获得同一互斥锁。在 C 中可以使用 std::recursive_mutex。
class Singleton {
private:Singleton() {} // 构造函数Singleton(const Singleton) delete; // 禁止拷贝Singleton operator(const Singleton) delete; // 禁止赋值public:static Singleton getInstance() {static Singleton instance; // 局部静态变量return instance;}
};
2.3.读写锁Read-Write Lock:
读写锁允许多个读线程同时访问共享资源但写线程在访问时会独占资源。C 标准库中没有直接提供读写锁但可以使用 std::shared_mutexC17 引入。
2.4.条件变量Condition Variable:
条件变量用于线程间的同步允许一个或多个线程在某个条件成立之前挂起等待。条件变量通常与互斥锁一起使用。
#include mutex
#include condition_variable
#include threadstd::mutex mtx;
std::condition_variable cv;
bool ready false;void print_id(int id) {std::unique_lockstd::mutex lock(mtx);while (!ready) {cv.wait(lock);}// 临界区std::cout Thread id \n;
}void go() {std::unique_lockstd::mutex lock(mtx);ready true;cv.notify_all();
}int main() {std::thread threads[10];for (int i 0; i 10; i)threads[i] std::thread(print_id, i);std::cout 10 threads ready to race...\n;go();for (auto th : threads) th.join();return 0;
}
2.5.原子操作Atomic Operations:
原子操作是不可分割的操作用于在没有互斥锁的情况下同步线程。C11 引入了 std::atomic 类模板提供了一种机制来保证操作的原子性。
#include atomic
#include threadstd::atomicint ai(0);void increment() {ai;
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}
2.6.屏障Barrier:
屏障是一种同步机制它允许一组线程相互等待直到所有线程都到达屏障点。
2.7.信号量Semaphore:
信号量是一种计数器用于控制对共享资源的访问数量。在 C 标准库中没有直接提供信号量但可以使用第三方库或者自定义实现。
2.8.纤程Fiber:
纤程是一种轻量级的线程通常用于协程的实现。在 C20 中引入了协程的支持可以通过纤程来实现非阻塞的同步。 重新设计类结构有时重新设计类的结构可以避免菱形继承例如通过使用组合而不是继承。 三、如何在c中创建和管理线程
在 C 中创建和管理线程涉及到几个关键步骤包括创建线程、执行任务、同步线程以及管理线程生命周期。以下是详细的步骤和示例代码
3.1.包含必要的头文件:
互斥锁用于保护临界区确保同一时间只有一个线程可以访问共享资源。在 C 中可以使用 std::mutex 来实现互斥锁。
#include iostream
#include thread
#include vector
#include mutex
#include condition_variable
3.2.创建线程:
使用 std::thread 类来创建线程。你可以将函数或者 lambda 表达式传递给 std::thread 的构造函数。
void print_id(int id) {std::cout Thread id std::endl;
}int main() {std::thread t1(print_id, 1);std::thread t2(print_id, 2);
}
3.3.等待线程结束:
使用 join() 方法等待线程结束。这会阻塞主线程直到指定的线程完成其任务。
t1.join();
t2.join();
3.4.分离线程:
使用 detach() 方法可以让线程在后台运行主线程可以继续执行而不需要等待它结束。
t1.detach();
t2.detach();
3.5.使用线程局部存储:
使用 thread_local 存储来定义线程特有的数据每个线程都有自己的独立副本。
thread_local int thread_local_data 0;void increment() {thread_local_data;std::cout Thread local data: thread_local_data std::endl;
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();
}
3.6.线程同步:
使用互斥锁std::mutex、条件变量std::condition_variable、原子操作std::atomic等同步机制来管理线程间的协作和资源共享。
std::mutex mtx;
std::condition_variable cv;
bool ready false;void print_message() {std::unique_lockstd::mutex lock(mtx);cv.wait(lock, []{ return ready; });std::cout Thread is ready to run std::endl;
}int main() {std::thread t1(print_message);{std::lock_guardstd::mutex lock(mtx);ready true;}cv.notify_one();t1.join();
}
3.7.线程同步:
对于需要管理大量线程的场景可以使用线程池来减少线程创建和销毁的开销。这里是一个简单的线程池示例
#include vector
#include queue
#include thread
#include mutex
#include condition_variable
#include functional
#include iostreamclass ThreadPool {
public:ThreadPool(size_t threads) : stop(false) {for(size_t i 0; i threads; i) {workers.emplace_back([this] {while(true) {std::functionvoid() task;{std::unique_lockstd::mutex lock(this-queue_mutex);this-condition.wait(lock, [this] { return this-stop || !this-tasks.empty(); });if(this-stop this-tasks.empty())return;task std::move(this-tasks.front());this-tasks.pop();}task();}});}}templateclass F, class... Argsauto enqueue(F f, Args... args) - std::futuretypename std::result_ofF(Args...)::type {using return_type typename std::result_ofF(Args...)::type;auto task std::make_sharedstd::packaged_taskreturn_type()(std::bind(std::forwardF(f), std::forwardArgs(args)...));std::futurereturn_type res task-get_future();{std::unique_lockstd::mutex lock(queue_mutex);if(stop)throw std::runtime_error(enqueue on stopped ThreadPool);tasks.emplace([task](){ (*task)(); });}condition.notify_one();return res;}~ThreadPool() {{std::unique_lockstd::mutex lock(queue_mutex);stop true;}condition.notify_all();for(std::thread worker: workers)worker.join();}private:std::vectorstd::thread workers;std::queuestd::functionvoid() tasks;std::mutex queue_mutex;std::condition_variable condition;bool stop;
};int main() {ThreadPool pool(4);auto result pool.enqueue([](int answer) { return answer; }, 42);std::cout The answer is result.get() std::endl;return 0;
}
3.8.线程同步:
在创建线程时可能会发生错误例如系统资源不足。可以通过检查 std::thread 对象的状态来处理这些错误。
std::thread myThread(task);
if (!myThread.joinable()) {// 处理错误
}
3.9.使用 C20 协程:
C20 引入了协程它提供了一种更轻量级的线程管理方式允许在单个线程内以非阻塞的方式执行多个任务。
#include coroutine
#include thread
#include iostreamgeneratorint GetNumbers() {for (int i 0; i 5; i) {co_yield i;}
}taskvoid RunGenerator() {for (auto n : GetNumbers()) {std::cout n std::endl;}
}int main() {std::jthread jthread(RunGenerator());jthread.join();return 0;
} 总结 菱形继承在 C 中菱形继承是一个常见的多重继承问题它可能导致二义性和资源浪费。通过使用虚继承virtual inheritance可以确保基类只有一个共享实例从而解决这个问题。 多线程同步机制C 提供了多种同步机制包括互斥锁mutexes、条件变量condition variables、原子操作atomic operations等以确保在多线程环境中对共享资源的安全访问。正确使用这些同步工具对于避免数据竞争和死锁至关重要。 创建和管理线程在 C 中可以通过 std::thread 创建线程并通过 join() 或 detach() 管理线程的生命周期。线程同步、线程局部存储和线程池等技术有助于高效地管理线程资源提高程序的性能和响应能力。
通过深入理解这些概念和机制开发者可以设计出更高效、更稳定且易于维护的多线程应用程序。随着 C 语言的不断发展新的功能和改进也在不断地被引入以支持更先进的并发编程模式。