精华内容
下载资源
问答
  • linux线程互斥量pthread_mutex_t使用简介

    万次阅读 多人点赞 2018-06-03 20:30:42
    为什么使用线程锁 在多线程应用程序中,当多个线程共享相同的内存时,如同时访问一个变量时,需要确保每个线程看到一致的数据视图,即保证所有线程对数据的修改是一致的。 如下两种情况不存在不一致的问题: 每...

    为什么使用线程锁

    在多线程应用程序中,当多个线程共享相同的内存时,如同时访问一个变量时,需要确保每个线程看到一致的数据视图,即保证所有线程对数据的修改是一致的。

    如下两种情况不存在不一致的问题:

    • 每个线程使用的变量都是其他线程不会读取和修改的
    • 变量是只读的

    当一个线程在修改变量的值时,其他线程在读取这个变量时可能会得到一个不一致的值。

    一个典型的例子是,在一个多线程程序中,两个及以上个线程对同一个变量i执行i++操作,结果得到的值并不如顺序执行所预期的那样。这就是线程间不同步的一个例子。

    可以用程序修改变量值时所经历的三个步骤解释这个现象:

    • 从内存单元读入寄存器
    • 在寄存器中对变量操作(加/减1)
    • 把新值写回到内存单元

    不能预期以上三步骤在一个总线周期内完成,所以也就不能指望多线程程序如预期那样运行。

    开始使用线程锁

    互斥量

    多线程程序中可能会存在数据不一致的情况,那么如何保证数据一致呢?可以考虑同一时间只有一个线程访问数据。互斥量(mutex)就是一把锁。

    多个线程只有一把锁一个钥匙,谁上的锁就只有谁能开锁。当一个线程要访问一个共享变量时,先用锁把变量锁住,然后再操作,操作完了之后再释放掉锁,完成。

    当另一个线程也要访问这个变量时,发现这个变量被锁住了,无法访问,它就会一直等待,直到锁没了,它再给这个变量上个锁,然后使用,使用完了释放锁,以此进行。

    这个即使有多个线程同时访问这个变量,也好象是对这个变量的操作是顺序进行的。

    互斥变量使用特定的数据类型:pthread_mutex_t,使用互斥量前要先初始化,使用的函数如下:

    #include <pthread.h>
    
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    

    简单的使用可以使用默认的属性初始化互斥量,函数的后一个参数设置为NULL即可。

    对互斥量加锁解锁的函数如下:

    #include <pthread.h>
    
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    int pthread_mutex_trylock(pthread_mutex_t *mutex);
    int pthread_mutex_unlock(pthread_mutex_t *mutex);
    

    函数pthread_mutex_trylock会尝试对互斥量加锁,如果该互斥量已经被锁住,函数调用失败,返回EBUSY,否则加锁成功返回0,线程不会被阻塞。

    避免死锁

    产生死锁的情况较多,如一个线程对变量a加锁后,试图对变量b加锁,另一个线程对变量b加了锁,试图对a加锁,这时两个线程都不释放锁,加不会加锁成功,造成两个线程处于死锁状态。

    可以在设计中避免死锁的发生。如使用 pthread_mutex_timedlock函数,该函数允许线程阻塞特定时间,如果加锁失败就会返回ETIMEDOUT。函数原型如下:

    #include <pthread.h>
    #include <time.h>
    
    int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timesec *restrict tsptr);
    

    读写锁

    读写锁与互斥量类似,但它允许更高的并行性。

    互斥量只有两种状态:锁住和未锁住,且一次只有一个线程可以对它加锁。

    读写锁可以有三种状态:读模式下加锁状态、写模式下加锁状态和不加锁状态。一次只有一个线程可以占有写模式的读写锁,但多个线程可以同时占有读模式的读写锁。

    读写锁非常适合于对数据结构读的次数远远大于写的情况。

    与互斥量相比,读写锁在使用之前必须初始化,在释放它们底层的内存之前必须销毁。使用读写锁相关的函数如下:

    #include <pthread.h>
    
    int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
    int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
    
    int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
    
    int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
    int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
    

    条件变量

    条件变量与互斥量一直使用时,允许线程以无竞争的方式等待特定的条件发生。条件变量是线程可用的另一种同步机制。

    条件本身是由互斥量保护的。线程在改变条件状态之前必须产生锁住互斥量,其他线程在获得互斥量之前不会到这种改变,因为互斥量必须在锁定以后才能计算条件。

    在使用条件变量之前必须先对它初始化。释放条件变量底层的内存空间之前,对条件变量反初始化。使用的相关函数如下:

    #include <pthread.h>
    
    int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
    int pthread_cond_destroy(pthread_cond_t *cond);
    
    int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
    

    自旋锁

    与互斥量类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等阻塞状态。当锁被持有的时间较短,而且线程不希望在重新调度上花费太多成本的情况下使用自旋锁。

    当自旋锁用在非抢占式内核中时是非常有用的,除了提供互斥机制以外,它们会阻塞中断,这样中断处理程序就不会让系统陷入死锁状态,因为它需要获取已被加锁的自旋锁。

    在用户层,自旋锁并不非常有用。很多互斥量的实现非常高效,甚至与采用自旋锁是同行效率的。

    使用自旋锁的相关函数如下。

    #include <pthread.h>
    
    int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
    int pthread_spin_destroy(pthread_spinlock_t *lock);
    
    int pthread_spin_lock(pthread_spinlock_t *lock);
    int pthread_spin_trylock(pthread_spinlock_t *lock);
    int pthread_spin_unlock(pthread_spinlock_t *lock);
    

    总结

    在多线程编程中,线程同步是必不可少的考虑环节。线程不同步导致的问题很难排查,甚至bug复现的都很困难。

    所以在多线程编程中,应该在设计中考虑到数据同步问题,保证变量视图的一致性,避免出现不一致性情况。


    参考资料:
    《UNIX环境高级编程》

    展开全文
  • 关于 ? extends T 和 ? super T 的存在意义和使用

    万次阅读 多人点赞 2019-03-01 21:04:52
    super T> 中 super 怎么 理解?与 extends 有何不同? <? extends T>和<? super T>是Java泛型中的“通配符(Wildcards)”和“边界(Bounds)”的概念。 <? extends T>:是指“上界通配符...

    问题来源:Java 泛型 <? super T> 中 super 怎么 理解?与 extends 有何不同?

     

    <? extends T><? super T>是Java泛型中的“通配符(Wildcards)”“边界(Bounds)”的概念。

    • <? extends T>:是指 “上界通配符(Upper Bounds Wildcards)”
    • <? super T>:是指 “下界通配符(Lower Bounds Wildcards)”

    为什么要用通配符和边界?

    使用泛型的过程中,经常出现一种很别扭的情况。比如按照题主的例子,我们有Fruit类,和它的派生类Apple类。

    class Fruit {}
    class Apple extends Fruit {}

    然后有一个最简单的容器:Plate类。盘子里可以放一个泛型的“东西”。我们可以对这个东西做最简单的“放”和“取”的动作:set( )和get( )方法。

    class Plate<T>{
        private T item;
        public Plate(T t){item=t;}
        public void set(T t){item=t;}
        public T get(){return item;}
    }

    现在我定义一个“水果盘子”,逻辑上水果盘子当然可以装苹果。

    Plate<Fruit> p=new Plate<Apple>(new Apple());

    但实际上Java编译器不允许这个操作。会报错,“装苹果的盘子”无法转换成“装水果的盘子”。

    error: incompatible types: Plate<Apple> cannot be converted to Plate<Fruit>

    所以我的尴尬症就犯了。实际上,编译器脑袋里认定的逻辑是这样的:

    • 苹果 IS-A 水果
    • 装苹果的盘子 NOT-IS-A 装水果的盘子

    所以,就算容器里装的东西之间有继承关系,但容器之间是没有继承关系的。所以我们不可以把Plate的引用传递给Plate。

    为了让泛型用起来更舒服,Sun的大脑袋们就想出了<? extends T><? super T>的办法,来让”水果盘子“和”苹果盘子“之间发生关系。

    什么是上界?

    下面代码就是“上界通配符(Upper Bounds Wildcards)”:

    Plate<? extends Fruit>

    翻译成人话就是:一个能放水果以及一切是水果派生类的盘子。再直白点就是:啥水果都能放的盘子。这和我们人类的逻辑就比较接近了。Plate<? extends Fruit>Plate<Apple>最大的区别就是:Plate<? extends Fruit>Plate<Fruit>以及Plate<Apple>的基类。直接的好处就是,我们可以用“苹果盘子”给“水果盘子”赋值了。

    Plate<? extends Fruit> p=new Plate<Apple>(new Apple());

    如果把Fruit和Apple的例子再扩展一下,食物分成水果和肉类,水果有苹果和香蕉,肉类有猪肉和牛肉,苹果还有两种青苹果和红苹果。

     

    //Lev 1
    class Food{}
    
    //Lev 2
    class Fruit extends Food{}
    class Meat extends Food{}
    
    //Lev 3
    class Apple extends Fruit{}
    class Banana extends Fruit{}
    class Pork extends Meat{}
    class Beef extends Meat{}
    
    //Lev 4
    class RedApple extends Apple{}
    class GreenApple extends Apple{}

     

    在这个体系中,上界通配符 Plate<? extends Fruit> 覆盖下图中蓝色的区域。

     

    什么是下界?

    相对应的,“下界通配符(Lower Bounds Wildcards)”:

    Plate<? super Fruit>

    表达的就是相反的概念:一个能放水果以及一切是水果基类的盘子。Plate<? super Fruit>Plate<Fruit>的基类,但不是Plate<Apple>的基类。对应刚才那个例子,Plate<? super Fruit>覆盖下图中红色的区域。

     

    上下界通配符的副作用

    边界让Java不同泛型之间的转换更容易了。但不要忘记,这样的转换也有一定的副作用。那就是容器的部分功能可能失效。

    还是以刚才的Plate为例。我们可以对盘子做两件事,往盘子里set()新东西,以及从盘子里get()东西。

    class Plate<T>{
        private T item;
        public Plate(T t){item=t;}
        public void set(T t){item=t;}
        public T get(){return item;}
    }

    上界<? extends T>不能往里存,只能往外取

    <? extends Fruit>会使往盘子里放东西的set( )方法失效。但取东西get( )方法还有效。比如下面例子里两个set()方法,插入Apple和Fruit都报错。

     

    Plate<? extends Fruit> p=new Plate<Apple>(new Apple());
        
    //不能存入任何元素
    p.set(new Fruit());    //Error
    p.set(new Apple());    //Error
    
    //读取出来的东西只能存放在Fruit或它的基类里。
    Fruit newFruit1=p.get();
    Object newFruit2=p.get();
    Apple newFruit3=p.get();    //Error

     

    原因是编译器只知道容器内是Fruit或者它的派生类,但具体是什么类型不知道。可能是Fruit?可能是Apple?也可能是Banana,RedApple,GreenApple?编译器在看到后面用Plate赋值以后,盘子里没有被标上有“苹果”。而是标上一个占位符:CAP#1,来表示捕获一个Fruit或Fruit的子类,具体是什么类不知道,代号CAP#1。然后无论是想往里插入Apple或者Meat或者Fruit编译器都不知道能不能和这个CAP#1匹配,所以就都不允许。

    所以通配符<?>和类型参数的区别就在于,对编译器来说所有的T都代表同一种类型。比如下面这个泛型方法里,三个T都指代同一个类型,要么都是String,要么都是Integer。

    public <T> List<T> fill(T... t);

    但通配符<?>没有这种约束,Plate<?>单纯的就表示:盘子里放了一个东西,是什么我不知道。

    所以题主问题里的错误就在这里,Plate<? extends Fruit>里什么都放不进去。

    下界<? super T>不影响往里存,但往外取只能放在Object对象里

    使用下界<? super Fruit>会使从盘子里取东西的get( )方法部分失效,只能存放到Object对象里。set( )方法正常。

     

    Plate<? super Fruit> p=new Plate<Fruit>(new Fruit());
    
    //存入元素正常
    p.set(new Fruit());
    p.set(new Apple());
    
    //读取出来的东西只能存放在Object类里。
    Apple newFruit3=p.get();    //Error
    Fruit newFruit1=p.get();    //Error
    Object newFruit2=p.get();

     

    因为下界规定了元素的最小粒度的下限,实际上是放松了容器元素的类型控制。既然元素是Fruit的基类,那往里存粒度比Fruit小的都可以。但往外读取元素就费劲了,只有所有类的基类Object对象才能装下。但这样的话,元素的类型信息就全部丢失。

    PECS原则

    最后看一下什么是PECS(Producer Extends Consumer Super)原则,已经很好理解了:

    • 频繁往外读取内容的,适合用上界Extends。
    • 经常往里插入的,适合用下界Super。

     

     

    来自知乎的另一个回答:
    链接:https://www.zhihu.com/question/20400700/answer/117624335

    java是单继承,所有继承的类构成一棵树。
    假设A和B都在一颗继承树里(否则super,extend这些词没意义)。
    A super B 表示A是B的父类或者祖先,在B的上面。
    A extend B 表示A是B的子类或者子孙,在B下面。

    由于树这个结构上下是不对称的,所以这两种表达区别很大。假设有两个泛型写在了函数定义里,作为函数形参(形参和实参有区别):

    1) 参数写成:T<? super B>,对于这个泛型,?代表容器里的元素类型,由于只规定了元素必须是B的超类,导致元素没有明确统一的“根”(除了Object这个必然的根),所以这个泛型你其实无法使用它,对吧,除了把元素强制转成Object。所以,对把参数写成这样形态的函数,你函数体内,只能对这个泛型做插入操作,而无法读

    2) 参数写成: T<? extends B>,由于指定了B为所有元素的“根”,你任何时候都可以安全的用B来使用容器里的元素,但是插入有问题,由于供奉B为祖先的子树有很多,不同子树并不兼容,由于实参可能来自于任何一颗子树,所以你的插入很可能破坏函数实参,所以,对这种写法的形参,禁止做插入操作,只做读取


    具体请看 《effective java》里,Joshua Bloch提出的PECS原则
    java - What is PECS (Producer Extends Consumer Super)?

    展开全文
  • java中\t使用

    万次阅读 多人点赞 2018-04-04 21:06:57
    为制表符,对齐时使用的)不过,关于这个问题,完全可以通过做试验找到答案的。最多8行程序就知道结果了。 "\t"意义如下:试验一:System.out.print("HI");结果是:HISystem.out.print("\...

    我用白话文解释"\t"的意思是:在同一个缓冲区内横向跳8个空格,JDK1.5上是这样的,至于更高版本是否变化,那我就不太清楚了!!(有时候也有书籍称"\t"为制表符,对齐时使用的)

    不过,关于这个问题,完全可以通过做试验找到答案的。最多8行程序就知道结果了。

     

    "\t"意义如下:

    试验一:

    System.out.print("HI");

    结果是:HI

    System.out.print("\t"+"HI");

    结果是:        HI

    你仔细算下,HI前面空了几个空格,用程序试验下!

    试验二:

     System.out.println("\t"+"HI");

     System.out.println("HI"+"\t"+"HI");

     System.out.println("        "+"HI");//此处的HI前有8个空格

     

    输出结果:

            HI

    HI      HI

            HI

    说明,如果"\t"之前无输出的数据,那直接横向跳8个空格,如果"\t"前有数据,那么连同前面的数据在内加上"\t"产生的空格跳越也是8个。(所以,我们称这种情况是在同一个缓冲区内)

    展开全文
  • 一、wchar_t类型的由来 我们知道char类型变量可以存储一个字节的字符,它用来保存英文字符和标点符号是可以的,但是对于汉字、韩文以及日文这样的字符却不可以,因为汉字、韩文以及...使用: wchar_t bob = L'p'; ...

    一、wchar_t类型的由来

         我们知道char类型变量可以存储一个字节的字符,它用来保存英文字符和标点符号是可以的,但是对于汉字、韩文以及日文这样的字符却不可以,因为汉字、韩文以及日文每一个文字都占据两个字节,为了解决这个问题,c++提出了wchar_t类型,称之为双字节类型,又称宽字符类型。可以通过加上前缀L来表示宽字符常量和宽字符串。

    使用: wchar_t  bob = L'p';

       wcout << L"tall" << endl;

    二、下面是一个范例

    #include <iostream>
    #include <locale>//setlocale函数在locale头文件中定义
    using namespace std;
    int main()
    {
     //使用setlocale函数将本机的语言设置为中文简体
     setlocale(LC_ALL,"chs");//LC_ALL表示设置所有的选项(包括金融货币、小数点,时间日期格式、语言字符串的使用习惯等),chs表示中文简体
     wchar_t wt[] = L"中";//大写字母L告诉编译器为"中"字分配两个字节的空间
     wcout<<wt<<endl;//使用wcout来代替cout输出宽字符
     return 0;
    }

    三、char16_t 和 char32_t的使用方法(C++11)

    char16_t  ch1 =u'q';

    char32_t ch2 = U'\U0000222B';


    三种类型都有底层类型(underlying),对底层类型的选择取决于实现,而底层类型可能随系统变化。

    展开全文
  • pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析

    万次阅读 多人点赞 2016-06-28 22:24:46
    int pthread_cond_init (pthread_cond_t* cond, pthread_condattr_t *cond_attr); /* 销毁一个条件变量 */ int pthread_cond_destroy(pthread_cond_t* cond); /* 令一个消费者等待在条件变量上 */ int pthread_...
  • Java之泛型<T> TT的用法-yellowcong

    万次阅读 2017-11-23 15:24:00
    `<T> T`表示返回值是一个泛型,传递啥,就返回啥类型的数据,而单独的`T`就是表示限制你传递的参数类型,这个案例中,通过一个泛型的返回方式,获取每一个集合中的第一个数据, 通过返回值`<T> T` 和`T`的两种方法...
  • Intel Realsense T265使用教程

    万次阅读 多人点赞 2020-11-09 14:47:42
    Intel Realsense T265使用教程1 T265参数2 T265 数据读取2.1 环境安装3、使用ROS包读取T265数据4、使用Opencv库读取T265数据参考资料 1 T265参数 T265采用了Movidius Myriad 2视觉处理单元(VPU),V-SLAM算法都直接...
  • RealSense T265使用教程

    千次阅读 2019-07-17 20:12:20
    RealSense ROS 安装 https://github.com/IntelRealSense/realsense-ros
  • SPSS中T检验的作用以及使用前提

    万次阅读 2019-05-03 23:35:46
    SPSS中的各种检验(作用、使用前提) 一、T检验 1.1 T检验的作用 T检验是用T分布理论来推论差异发生的概率,从而比较两组平均数的差异是否显著。 注:只能比较两组平均数,随着检验次数的增加,检验水准不再是0.05也...
  • 泛型的基础使用实例,包括泛型类,泛型参数,泛型方法。泛型返回值,等的实际例子都有举例。以及,实际编码中什么时候使用泛型。讲解的很清楚。
  •   在搞网络这一块的时候,看到了100Base-T、100Base-TX等这些东西,在IEEE802.3中,也到处是这些词。大体了解了一下,下面是正文。   以太网采用CSMA/CD(Carrier Sense Multiple Access/Collision Detection,...
  • TypeScript 泛型<T>使用整理

    千次阅读 2017-06-28 15:54:31
    一、介绍 相C#和Java等以上,TypeScript可以使用泛型来创建可重用的组件。支持当前数据类型,同时也能支持未来的数据类型。...function identity(arg:T):T{ console.log(typeof arg); return arg
  • JAVA T 范型使用例子

    千次阅读 2018-09-30 16:02:09
    public <T> T getResultData(Result<?> result,Class<T> clazz) { T ret = null ; if (result != null) { if (!ResultEnum.SUCCESS.code.equals(result.getRetCode())) { ...
  • Python中制表符\t使用

    千次阅读 多人点赞 2020-09-29 09:24:09
    以前一直以为制表符只是输出八个空格,实际上是补齐8... 代码 print("w\t*") print("ww\t*") print("www\t*") print("wwww\t*") print("wwwww\t*") print("wwwwww\t*") print("wwwwwww\t*") print("wwwwwwww\t*") 结果
  • JAVA&Lombok Builder模式 泛型<T使用

    千次阅读 2021-03-30 14:34:29
    T> 使用 @Data @Builder public class ResponseResultVO<T> { private long code; private String msg; private T data; } 1、Lombok Builder 使用 ResponseResultVO<SysUsers> vo = ...
  • List<T>的使用

    万次阅读 2018-01-31 14:24:24
    List的使用 定义:List类表示可通过索引访问的对象的强类型列表,提供用于对列表进行搜索、排序和操作的方法。 作用: 泛型最常见的用途是泛型集合 我们在创建列表类时,列表项的数据类型可能是int,string...
  • w.r.t:with respect to的缩写,意思是关于、谈到、涉及等。 i.e.:id est的缩写,意思是即,换句话说等。 et al. :et alia(“and others;and co-workers”)的缩写,意思是:其他人、等人。通常在列文献作者时...
  • 提起配对t检验的适用条件,大家都知道,有人问配对样本T检验的假设前提是什么,另外,还有人想问t检验的应用条件是什么,你知道这是怎么回事?其实两独立样本T检验的适用范围是什么,下面就一起来看看独立样本T检验...
  • 如何正确区分方差分析、T检验、卡方检验的使用

    万次阅读 多人点赞 2019-07-24 13:07:03
    差异研究的目的在于比较两组...如果是定类和定量,此时应该使用方差或者T检验。 方差和T检验的区别在于,对于T检验的X来讲,其只能为2个类别比如男和女。如果X为3个类别比如本科以下,本科,本科以上;此时只能使用...
  • A2W、W2A、A2TT2A的使用方法

    万次阅读 2015-07-09 09:26:06
    1、A2W和W2A  在《Window核心编程》,多字节和宽字节之间转换比较麻烦的,...那么使用ATL的一个很好的字符串的转换宏:A2W和W2A。  (1)A2W的用法: USES_CONVERSION;CString tmpStr;char* LineChar="fd
  • 使用Excel计算T检测的具体操作步骤

    万次阅读 2018-04-24 17:37:37
     第四个参数用于定义t-检验类型:1代表成对检验,2代表双样本等方差假设,3代表双样本异方差假设  第一参数和第二参数你就要输入数组形式的参数呀,也就是一列,或一行  第三个参数和第四参数就看你的要求的,以...
  • OmegaT使用Java语言编写的开源免费计算机辅助翻译(CAT)软件。在CAT软件中,使用最为广泛的当属SDL Trados,Trados的功能十分强大,但是它是收费软件,且价格不低。再说国产的雪人CAT,虽有免费版,但免费版的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,676,101
精华内容 1,870,440
关键字:

\t的使用