首页 > 其他分享 >第2章 线程同步精要

第2章 线程同步精要

时间:2023-04-01 21:34:19浏览次数:34  
标签:同步 lock 加锁 线程 mutex 精要 Foo

第2章 线程同步精要

线程同步的四项原则,按重要性排列:

  • 1.首要原则是尽量最低限度地共享对象,减少需要同步的场合。一个对象能不暴露给别的线程就不要暴露;如果要暴露,优先设置对象不可更改;实在不行才暴露可修改的对象,并用同步措施来充分保护它。
  • 2.其次是使用高级的并发编程构件,如TaskQueue、Producer- Consumer Queue、CountDownLatch等等。
  • 3.最后不得已必须使用底层同步原语(primitives)时,只用非递归的互斥器和条件变量,慎用读写锁,不要用信号量。
  • 4.除了使用atomic整数之外,不自己编写lock-free代码3,也不要用“内核级”同步原语4 5。不凭空猜测“哪种做法性能会更好”,比如spin lock vs. mutex。

2.1 互斥器(mutex)

单独使用mutex时,我们主要为了保护共享数据。我个人的原则是:

  • 使用unique_lock管理mutex,使用构造和析构函数来进行加锁和解锁,而不是自己收到加锁和解锁。
  • 只用非递归的mutex(即不可重入的mutex)。
  • unique_lock对象一般设置为栈上对象,然后看函数调用栈就能分析用锁的情况,非常便利。【不懂】

次要原则有:

  • 不使用跨进程的mutex,进程间通信只用TCP sockets。
  • 加锁、解锁在同一个线程,线程a不能去unlock线程b已经锁住的mutex(unique_lock自动保证)。
  • 必要的时候可以考虑用PTHREAD_MUTEX_ERRORCHECK来排错。【不懂】

2.1.1 只使用非递归的mutex

在同一个线程里多次对non-recursive mutex加锁会立刻导致死锁,我认为这是它的优点,能帮助我们思考代码对锁的期求,并且及早(在编码阶段)发现问题。
recursive mutex可能会隐藏代码里的一些问题。典 型情况是你以为拿到一个锁就能修改对象了,没想到外层代码已经拿 到了锁,正在修改(或读取)同一个对象呢。如下:

#include "../Mutex.h"
#include "../Thread.h"
#include <vector>
#include <stdio.h>

using namespace muduo;

class Foo
{
 public:
  void doit() const;
};

MutexLock mutex;
std::vector<Foo> foos;

void post(const Foo& f)
{
  MutexLockGuard lock(mutex);
  foos.push_back(f);
}

void traverse()
{
  MutexLockGuard lock(mutex);
  for (std::vector<Foo>::const_iterator it = foos.begin();
      it != foos.end(); ++it)
  {
    it->doit();
  }
}

void Foo::doit() const
{
  Foo f;
  post(f);
}

int main()
{
  Foo f;
  post(f);
  traverse();
}

这个例子说明了什么????

标签:同步,lock,加锁,线程,mutex,精要,Foo
From: https://www.cnblogs.com/codingbigdog/p/17279438.html

相关文章

  • 实现Callable接口创建线程
    ​ 通过实现Callable接口创建线程与实现Runnable接口创建线程类似,不同之处在于Callable的call()方法可以返回一个结果,并且可以抛出异常。以下是通过实现Callable接口创建线程的示例代码:importjava.util.concurrent.Callable;publicclassMyCallableimplementsCallable<Str......
  • 通过线程池的方式获取线程
    ​ 使用线程池可以更好地管理线程的数量,避免线程数量过多导致系统性能下降的问题。Java中提供了Executor框架,可以很方便地创建和管理线程池。以下是使用线程池的示例代码:importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassMa......
  • Java创建线程的三种方式
    创建线程的三种方式1.继承Thread类,重写run方法publicclassMyThreadextendsThread{publicvoidrun(){System.out.println("HellofromMyThread!");}}publicclassMain{publicstaticvoidmain(String[]args){MyThreadthread......
  • Java线程:wait()和notify()
    一、wait()和notify()含义二、标准代码示例创建两个线程Thread0和Thread1。代码实现:运行流程详解三、什么时候释放锁—wait()、notify()四、用生活故事讲懂线程的等待唤醒1.老王和老李(专家程序员):2.王哥和李哥(普通程序员):3.小王和小李(新手程序员):五、问题理解1、执行wait()的......
  • 多线程
    内容什么是线程如何创建线程线程的调度线程的一个设计模式:生产消费者模型线程池线程集合对象(侧重点)一、什么是线程进程:运行中的程序才可以称为进程,一个程序一个进程。宏观并行,微观串行。线程:1.任何一个程序都至少拥有一个线程,即主线程。但是java程序默认有两个线......
  • C# 直接在子线程中对窗体上的控件操作是会出现异常
    https://www.bbsmax.com/A/MAzA8klpd9/ Form1里privatedelegatevoidDispMSGDelegate(intindex,stringMSG);publicvoidDispMsg(intiIndex,stringstrMsg){if(this.richTextBox1.InvokeRequired==false)......
  • 线程停止
    线程停止1.建议线程正常停止--->利用次数,不建议死循环2.建议使用标志位--->设置一个标志位3.不要使用stop或者destroy等过时或者JDK不建议使用的方法//测试stop//1.建议线程正常停止--->利用次数,不建议死循环//2.建议使用标志位--->设置一个标志位//3.不要使用stop或者dest......
  • 线程休眠
    模拟网络延时放大问题的发生性//模拟网络延时:放大问题的发生性publicclassTestSleepimplementsRunnable{//票数privateintticketNums=10;@Overridepublicvoidrun(){while(true){if(ticketNums<=0){......
  • 线程
    目录线程线程概念的引入背景进程有了进程为什么要有线程进程和线程创建线程创建线程的两种方式参数和方法Thread类中的几个方法如何开启多线程进程和线程的比较1.pid不同2.开启效率的不同3.内存数据的共享不同多线程实现socket守护线程GIL锁(全局解释器锁)验证GIL的存在GIL与普通......
  • Java多线程(一篇从0讲透)
    多线程思维导图看天下:1.概述并行与并发并行:指两个或多个事件在同一时刻发生(同时发生)并发:指两个或多个事件在同一个时间段内发生。(交替执行)线程与进程进程:是指一个内存中运行的程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程记忆:进程的英文......