当前位置: 首页 > news >正文

网站后台管理系统展望创意网页设计

网站后台管理系统展望,创意网页设计,公司网站毕业设计论文,织梦网站栏目管理悲观锁 悲观锁认为在并发环境中#xff0c;数据随时可能被其他线程修改#xff0c;因此在访问数据之前会先加锁#xff0c;以防止其他线程对数据进行修改。常见的悲观锁实现有#xff1a; 1.互斥锁 原理#xff1a;互斥锁是一种最基本的锁类型#xff0c;同一时间只允…悲观锁 悲观锁认为在并发环境中数据随时可能被其他线程修改因此在访问数据之前会先加锁以防止其他线程对数据进行修改。常见的悲观锁实现有 1.互斥锁 原理互斥锁是一种最基本的锁类型同一时间只允许一个线程访问共享资源。当一个线程获取到互斥锁后其他线程如果想要访问该资源就必须等待锁被释放。 应用场景适用于写操作频繁的场景如数据库中的数据更新操作。在 C 中可以使用 std::mutex 来实现互斥锁示例代码如下 #include iostream #include mutex #include threadstd::mutex mtx; int sharedResource 0;void increment() {std::lock_guardstd::mutex lock(mtx);sharedResource; }int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout Shared resource: sharedResource std::endl;return 0; } 2.读写锁 原理读写锁允许多个线程同时进行读操作但在进行写操作时会独占资源不允许其他线程进行读或写操作。读写锁分为读锁和写锁多个线程可以同时获取读锁但写锁是排他的。 应用场景适用于读多写少的场景如缓存系统。在 C 中可以使用 std::shared_mutex 来实现读写锁示例代码如下  #include iostream #include shared_mutex #include threadstd::shared_mutex rwMutex; int sharedData 0;void readData() {std::shared_lockstd::shared_mutex lock(rwMutex);std::cout Read data: sharedData std::endl; }void writeData() {std::unique_lockstd::shared_mutex lock(rwMutex);sharedData;std::cout Write data: sharedData std::endl; }int main() {std::thread t1(readData);std::thread t2(writeData);t1.join();t2.join();return 0; } 乐观锁 乐观锁是一种在多线程环境中避免阻塞的同步技术它假设大部分操作是不会发生冲突的因此在操作数据时不会直接加锁而是通过检查数据是否发生了变化来决定是否提交。如果在提交数据时发现数据已被其他线程修改则会放弃当前操作重新读取数据并重试。 应用场景适用于读多写少、冲突较少的场景如电商系统中的库存管理。 在 C 中乐观锁的实现通常依赖于版本号或时间戳的机制。每个线程在操作数据时会记录数据的版本或时间戳操作完成后再通过比较版本号或时间戳来判断是否发生了冲突。 下面是一个使用版本号实现乐观锁的简单示例代码 #include iostream #include thread #include atomic #include chrono// 共享数据结构 struct SharedData {int value; // 数据的实际值std::atomicint version; // 数据的版本号用于检查是否发生了修改 };// 线程安全的乐观锁实现 bool optimisticLockUpdate(SharedData data, int expectedVersion, int newValue) {// 检查数据的版本号是否与预期一致if (data.version.load() expectedVersion) {// 进行数据更新data.value newValue;// 增加版本号data.version.fetch_add(1, std::memory_order_relaxed);return true; // 成功提交更新}return false; // 数据版本不一致操作失败 }void threadFunction(SharedData data, int threadId) {int expectedVersion data.version.load();int newValue threadId * 10;std::cout Thread threadId starting with version expectedVersion ...\n;std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟工作// 尝试更新数据if (optimisticLockUpdate(data, expectedVersion, newValue)) {std::cout Thread threadId successfully updated value to newValue \n;} else {std::cout Thread threadId failed to update (version mismatch)\n;} }int main() {// 初始化共享数据值为 0版本号为 0SharedData data{0, 0};// 启动多个线程进行乐观锁测试std::thread t1(threadFunction, std::ref(data), 1);//std::ref(data) 将 data 包装成一个引用包装器确保 data 在传递给函数时以引用的方式传递而不是被复制。std::thread t2(threadFunction, std::ref(data), 2);std::thread t3(threadFunction, std::ref(data), 3);t1.join();t2.join();t3.join();std::cout Final value: data.value , Final version: data.version.load() \n;return 0; } 原子锁 原子锁是一种基于原子操作如CAS、test_and_set的锁机制。与传统的基于互斥量如 std::mutex的锁不同原子锁依赖于硬件提供的原子操作允许对共享资源的访问进行同步且通常比传统锁更加高效。它通过原子操作保证对共享资源的独占访问而不需要显式的线程调度。 原子锁的适用场景 1.简单数据类型原子锁最常用于锁定简单的基础数据类型例如整数、布尔值、指针等。通过原子操作多个线程可以安全地对这些数据进行读写而不会发生数据竞争。 示例std::atomicint, std::atomicbool, std::atomiclong long 2.计数器、标志位当需要在多线程中维护计数器、标志位或状态变量时原子操作非常合适。例如当多个线程需要递增计数器时可以用原子操作避免使用传统的互斥锁。 示例使用 std::atomicint 来维护线程安全的计数器。 注原子锁通常不能锁容器类型。 什么是原子操作 原子操作是指不可分割的操作在执行过程中不会被中断或干扰。原子操作保证了操作的完整性要么完全执行要么完全不执行避免了在操作过程中被线程切换打断从而避免了数据竞争和不一致的情况。 1.自旋锁 什么是自旋锁 自旋锁是一种使用原子操作来检测锁是否可用的锁机制。自旋锁是一种忙等待的锁当线程尝试获取锁失败时会不断地检查锁的状态直到成功获取锁。  在 C 中可以使用 std::atomic_flag 结合 test_and_set 操作来实现一个简单的自旋锁 test_and_set 是一个原子操作它会检查一个布尔标志的值然后将该标志设置为 true。整个操作过程是不可分割的即不会被其他线程的操作打断。这个布尔标志通常被用作锁线程通过检查并设置这个标志来尝试获取锁。 工作原理 检查标志状态线程首先检查布尔标志的当前值。设置标志为 true如果标志当前为 false表示锁未被占用线程将标志设置为 true表示成功获取到锁如果标志当前为 true表示锁已被其他线程占用线程未能获取到锁。返回旧值test_and_set 操作会返回标志的旧值。线程可以根据这个返回值判断是否成功获取到锁。如果返回 false说明成功获取到锁如果返回 true则需要等待锁被释放后再次尝试获取。 #include iostream #include atomic #include thread #include vectorstd::atomic_flag lock ATOMIC_FLAG_INIT;// 自旋锁类 class SpinLock { public:void lock() {// 持续尝试获取锁直到成功while (lock.test_and_set(std::memory_order_acquire)) {// 自旋等待}}void unlock() {// 释放锁将标志设置为 falselock.clear(std::memory_order_release);} };SpinLock spinLock; int sharedResource 0;// 线程函数 void worker() {for (int i 0; i 100000; i) {spinLock.lock();sharedResource;spinLock.unlock();} }int main() {std::vectorstd::thread threads;// 创建多个线程for (int i 0; i 4; i) {threads.emplace_back(worker);}// 等待所有线程完成for (auto thread : threads) {thread.join();}std::cout Shared resource value: sharedResource std::endl;return 0; } 自旋锁优点 无上下文切换自旋锁不会引起线程挂起因此避免了上下文切换的开销。在锁竞争较轻时自旋锁可以高效地工作。 简单高效实现简单且不依赖操作系统调度适合锁竞争不严重的场景。 自旋锁缺点 CPU资源浪费如果锁被占用自旋锁会不断地循环检查锁的状态浪费 CPU 时间尤其是在锁持有时间较长时可能导致性能问题。 不适合锁竞争场景当有大量线程竞争同一个锁时自旋锁的性能将大幅下降因为大部分时间都在自旋浪费了 CPU 资源。 自旋锁的适用场景 短时间锁竞争自旋锁适用于临界区代码执行时间非常短的情况。如果锁持有时间较长使用自旋锁就不合适了。 锁竞争较轻在多线程程序中如果线程数量较少且资源竞争较少自旋锁可以有效减少线程上下文切换提升性能。 实时系统或高性能系统在某些对延迟非常敏感的应用场景中自旋锁可以通过减少上下文切换来提供更低的延迟。 总结自旋锁是一种简单且高效的锁机制通过原子操作避免了线程上下文切换适合用于短时间锁竞争和低延迟要求的场景。在锁竞争激烈或锁持有时间较长时自旋锁的性能会受到影响这时传统的互斥锁如 std::mutex可能更为合适。 递归锁 在 C 中递归锁也被称为可重入锁它是一种特殊的锁机制允许同一个线程多次获取同一把锁而不会产生死锁。 原理 普通的互斥锁如 std::mutex不允许同一个线程在已经持有锁的情况下再次获取该锁否则会导致死锁。因为当线程第一次获取锁后锁处于被占用状态再次尝试获取时由于锁未被释放线程会被阻塞而该线程又因为被阻塞无法释放锁从而陷入死循环。 递归锁则不同它内部维护了一个计数器和一个持有锁的线程标识。当一个线程第一次获取递归锁时计数器加 1同时记录该线程的标识。如果该线程再次请求获取同一把锁计数器会继续加 1而不会被阻塞。当线程释放锁时计数器减 1直到计数器为 0 时锁才会真正被释放其他线程才可以获取该锁。 应用场景 递归调用在递归函数中如果需要对共享资源进行保护使用递归锁可以避免死锁问题。例如在一个递归遍历树结构的函数中可能需要对树节点的某些属性进行修改此时可以使用递归锁来保证线程安全。嵌套锁当代码中存在多层嵌套的锁获取操作且这些操作可能由同一个线程执行时递归锁可以避免死锁。例如一个函数内部调用了另一个函数这两个函数都需要获取同一把锁。 注意事项 1. 性能开销 递归锁的实现比普通互斥锁更为复杂。普通互斥锁只需简单地标记锁的占用状态当一个线程请求锁时检查该状态并进行相应操作。而递归锁除了要维护锁的占用状态还需要记录持有锁的线程标识以及一个计数器用于跟踪同一个线程获取锁的次数。每次获取和释放锁时都需要对这些额外信息进行更新和检查这无疑增加了系统的开销。 时间开销由于额外的状态检查和更新操作递归锁的加锁和解锁操作通常比普通互斥锁更耗时。在高并发、对性能要求极高的场景下频繁使用递归锁可能会成为性能瓶颈。资源开销记录线程标识和计数器需要额外的内存空间虽然这部分开销相对较小但在资源受限的系统中也可能会产生一定的影响。 建议在不需要递归获取锁的场景下应优先使用普通互斥锁如 std::mutex。 2. 死锁风险 虽然递归锁允许同一个线程多次获取同一把锁而不会死锁但如果在递归调用过程中锁的获取和释放逻辑出现错误仍然可能导致死锁。例如在递归函数中获取锁后在某些条件下没有正确释放锁就进行了递归调用可能会导致锁无法正常释放其他线程请求该锁时就会陷入死锁。 #include iostream #include thread #include mutexstd::recursive_mutex recMutex;void faultyRecursiveFunction(int n) {if (n 0) return;std::lock_guardstd::recursive_mutex lock(recMutex);std::cout Recursive call: n std::endl;if (n 2) {// 错误没有释放锁就返回可能导致死锁return;}faultyRecursiveFunction(n - 1); }int main() {std::thread t(faultyRecursiveFunction, 3);t.join();return 0; }3.不同递归锁之间的交叉锁定 当存在多个递归锁时如果不同线程以不同的顺序获取这些锁就可能会产生死锁。例如线程 A 先获取了递归锁 L1然后尝试获取递归锁 L2而线程 B 先获取了递归锁 L2然后尝试获取递归锁 L1。此时两个线程都在等待对方释放锁从而陷入死锁状态。 在 C 标准库中std::recursive_mutex 是递归锁的实现。以下是一个简单的示例代码 #include iostream #include thread #include mutexstd::recursive_mutex recMutex;// 递归函数多次获取递归锁 void recursiveFunction(int n) {if (n 0) return;// 加锁std::lock_guardstd::recursive_mutex lock(recMutex);std::cout Recursive call: n std::endl;// 递归调用recursiveFunction(n - 1);// 锁在离开作用域时自动释放 }int main() {std::thread t(recursiveFunction, 3);t.join();return 0; }什么是锁的重入与不可重入 可重入锁也叫递归锁允许同一个线程在已经持有该锁的情况下再次获取同一把锁而不会产生死锁。可重入锁内部会维护一个持有锁的线程标识和一个计数器。当线程第一次获取锁时会记录该线程的标识并将计数器初始化为 1。如果该线程再次请求获取同一把锁锁会检查请求线程的标识是否与当前持有锁的线程标识相同如果相同则将计数器加 1而不会阻塞该线程。释放锁时计数器减 1直到计数器为 0 时锁才会释放其他线程才可以获取该锁。 不可重入锁不允许同一个线程在已经持有该锁的情况下再次获取同一把锁。如果一个线程已经持有了不可重入锁再次请求获取该锁时会导致线程阻塞进而可能产生死锁。不可重入锁只关注锁的占用状态不记录持有锁的线程标识和获取锁的次数。当一个线程请求获取锁时锁会检查其是否已被占用如果已被占用无论请求线程是否就是持有锁的线程都会将该线程阻塞。
http://www.hkea.cn/news/14382416/

相关文章:

  • 公司地址查询网站wordpress更换新主题
  • 常州网站关键词佛山网站建设联系电话
  • 高新网站设计找哪家广州专业网站设计公司
  • 域名网站上海建筑设计院工资
  • 免费行情网站链接做设计的软件
  • 余姚市网站建设免费留电话的广告
  • 娱乐类网站运动鞋网页ui设计
  • 买到域名网站怎么做设计工作室取什么名字好
  • 用网站ip做代理小吃加盟网站大全
  • 哈尔滨企业制作网站三门峡做网站
  • 仿制网站的后台建材在线
  • 做设计适合关注的网站mysql创建WordPress
  • 专业做展会网站建立网站的平台
  • 建设自己的网站有什么外贸网站哪个好
  • 内江建网站宝安最好的网站建设
  • 做销售的网站网站开发技术文档
  • 北京网站优化推广效果品牌线上推广方式
  • 网站建设大作业有代码网络舆情处置工作方案
  • 网站建设从入门到精通 网盘网站做美工
  • wordpress主题更新教程上海seo顾问推推蛙
  • 动力启航做网站代码外包平台
  • 上传附件空间网站建设路84号 网站备案
  • 重庆教育建设有限公司网站网站规划与建设实验心得
  • 软件网站排行榜东莞建设有限公司
  • 建设银行网站维修图片安徽省建设项目 备案网站
  • 红安建设局官方网站做个公司网站要多少钱
  • 网站开发是做什么模板网字库
  • 个人无网站怎样做cps广告apple网站设计
  • 江西锦宇建设集团有限公司网站自带代理的浏览器
  • 网站建设制作设计推广优化网站的做