一、线程概念

  1. 基础

    线程又称LWP:light weight process 轻量级的进程,(在linux环境下)本质仍是进程。进程:独立地址空间,拥有PCB
    线程:有独立的PCB,但没有独立的地址空间(共享)区别:在于是否共享地址空间。  独居(进程);合租(线程)Linux下:线程:最小的执行单位进程:最小分配资源单位,可看成是只有一个线程的进程GDB和信号诞生时间比线程早,故配合使用会很麻烦。线程越多的程序理论上越可能争夺到cpu资源,但不是一味的扩展线程数,会有峰值。ps -Lf 进程id //查看线程运行情况 包括线程号(cpu执行的最小单位,不等同于线程id)
    
  2. linux内核线程实现原理(了解即可)

    1.轻量级进程(lwp),也有PCB,创建线程使用的底层函数和进程一样,都是clone。
    2.从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存大额三级页表是相同的(详见下面三级映射)。
    3.进程可以锐变成线程
    4.线程可看做寄存器和栈的集合
    5.linux下,线程是最小执行单位,进程是最小分配资源单位三级映射:进程PCB->页目录(可看成数组,首地址位与PCB中)->页表->物理页面->内存单元。PCB中由三级映射出物理地址。 PCB中描述虚拟地址的指针指向一个【页面】(页面中都是指针),这个页面中的指针再指向一个【页表】(页表中也都是指针),页表再对应一个【页目录】(页目录中都是内存单元(对应物理内存))。多进程:每个进程对应不同的PCB,且有不同的页面指针。故不共享数据。多线程:每个线程对应不同的PCB,但有相同的页面指针。故共享数据。
    

  3. 线程共享资源

    1.文件描述符表
    2.每种信号的处理方式 (线程和信号尽可能不混用)
    3.当前工作目录
    4.用户ID 和 组ID
    5.内存地址空间(.text/.data/.bss/heap/共享库,栈不共享)
    
  4. 线程非共享资源

    1.线程ID
    2.处理器现场(寄存器相关)和栈指针(内核栈)
    3.独立的栈空间(用户空间栈)
    4.errno 变量
    5.信号屏蔽字
    6.调度优先级
    
  5. 线程优、缺点

二、线程控制原语(相关函数)

线程相关函数出错都返回errno,
故利用char * strerror(errno)函数来打印出错误信息。
而不用perror()。
  1. pthread_self

       man 3 pthread_self1)NAMEpthread_self - obtain ID of the calling thread2)SYNOPSIS#include <pthread.h>pthread_t pthread_self(void);Compile and link with -pthread.  //特别注意3)RETURN VALUEThis function always succeeds, returning the calling thread's ID.
  2. pthread_create

    man 3 pthread_create1)NAMEpthread_create - create a new thread2)SYNOPSIS#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);Compile and link with -pthread. //特别注意3)PARAMETER(1)thread:值结果参数,线程ID。(2)attr:设置线程属性。NULL表示使用默认属性(共两种属性)PTHREAD_CREATE_JOINABLE,可配合pthread_join()使用;另一种属性为PTHREAD_CREATE_DETACHED,不能配合pthread_join()使用,会报错。详见下 7.(3)start_routine:子线程回调函数。若线程创建成功,该函数自动被调用。(4)arg:start_routine指定函数的参数。没有的话传NULL。传参时一定要注意,不要传地址(数据共享原因),要传值进去,否则当回调函数得到数据时会出错。4)RETURN VALUEOn success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread.c循环创建多个线程DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_muti.c
  3. pthread_exit

    exit(0); //退出当前进程
    return 0;//返回到调用者那里去。//main函数中的return就代表进程结束。
    pthread_exit(0); //退出当前线程man 3 pthread_exit1.NAMEpthread_exit - terminate calling thread2.SYNOPSIS#include <pthread.h>void pthread_exit(void *retval);Compile and link with -pthread.3.PARAMETERretval:返回值。类似于exit(0);中的0.4.RETURN VALUEThis function does not return to the caller.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_muti.c
    
  4. pthread_join

    man 3 pthread_join1.NAMEpthread_join - join with a terminated thread2.SYNOPSIS#include <pthread.h>int pthread_join(pthread_t thread, void **retval);Compile and link with -pthread.
    3.PARAMETERthread:线程IDretval:值结果参数,得到pthread_create指定的线程回调函数的结果。为什么是(viod**)的返回类型。因为回调函数是void *,而再回调void* 就是void**.类似的wait回收int型数据为 int ——> int *则有           void* ——> void **注意:当线程被pthread_cancel()后,retval的值是-1,代表线程非正常消亡4.RETURN VALUEOn success, pthread_join() returns 0; on error, it returns an error number.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_join.c
    
  5. pthread_cancel

    man 3 pthread_cancel1.NAMEpthread_cancel - send a cancellation request to a thread2.SYNOPSIS#include <pthread.h>int pthread_cancel(pthread_t thread);Compile and link with -pthread.3.PARAMETERthread:指定要取消的进程ID4.RETURN VALUEOn success, pthread_cancel() returns 0; on error, it returns a nonzero error number.5.注意只有程序运行到取消点后(取消点函数执行完毕)才会取消,如果线程运行中(指回调函数)没有取消点,那就一直执行,不会取消。当程序中没有取消点时,可自行增加取消点,利用函数pthread_testcancel()。 //man pthread_testcancel取消点( man pthreads 中可查看):一些和内核进行交互的函数,如sleep()、close()等等常用的函数.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_cancel.c
    
  6. pthread_detach

    
    man 3 pthread_detach
    创建完线程后再指定线程分离,线程执行完自行回收,不能和pthread_join同时使用。1.NAMEpthread_detach - detach a thread2.SYNOPSIS#include <pthread.h>int pthread_detach(pthread_t thread);Compile and link with -pthread.3.RETURN VALUEOn success, pthread_detach() returns 0; on error, it returns an error number.Demo:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_detach.c
    
  7. pthread_create 参数2设置线程属性

    简单步骤:pthread_attr_t attr;//创建线程属性结构体pthread_attr_init(&attr);//初始化结构体pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//设置线程属性结构体为 detach 状态pthread_create(&tid,&attr,tfunc,NULL);//利用线程属性结构体创建线程pthread_attr_destroy(&attr);//在利用完线程属性结构体后销毁该结构体函数详解:(1)pthread_attr_init()、pthread_attr_destroy()man 3 pthread_attr_init1.NAMEpthread_attr_init, pthread_attr_destroy - initialize and destroy thread attributes object2.SYNOPSIS#include <pthread.h>int pthread_attr_init(pthread_attr_t *attr);   //类似malloc()int pthread_attr_destroy(pthread_attr_t *attr); //类似free()Compile and link with -pthread.3.RETURN VALUEOn success, these functions return 0; on error, they return a nonzero error number.(2)pthread_attr_setdetachstate()、pthread_attr_getdetachstate()1.NAMEpthread_attr_setdetachstate, pthread_attr_getdetachstate - set/get detach state attribute in thread attributes object2.SYNOPSIS#include <pthread.h>int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);Compile and link with -pthread.3.PARAMETER1)attr2)detachstate:PTHREAD_CREATE_DETACHEDThreads that are created using attr will be created in a detached state.PTHREAD_CREATE_JOINABLEThreads that are created using attr will be created in a joinable state.attention:The default setting of the detach state attribute in a newly initialized thread attributes object is PTHREAD_CREATE_JOIN‐ABLE.4.RETURN VALUEOn success, these functions return 0; on error, they return a nonzero error number.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_attr_init.c
    
  8. 线程使用相关注意事项

    1.主线程退出其他线程不退出,主线程应调用pthread_exit。
    2.避免僵尸进程有两种方法:1)pthread_join //线程创建默认属性2)pthread_detach //需指定设置,两种设置方法1.pthread_create()时利用线程属性指定2.pthread_create()后指定。
    3.malloc和mmap申请的内存可以被其他线程释放。
    4.应避免在多线程中调用fork(),子进程中只有调用fork的线程存在,其他线程在子进程均pthread_exit().
    5.应避免在多线程中引入信号机制。理由:每个线程有独立的PCB,故mask(屏蔽字集合)不同,但每个线程对信号的处理是共享的(因为在一个进程下),而由哪个线程来获取信号是靠CPU分配的,而当一个线程处理完之后,其他线程是不受影响的。
    

三、线程和进程控制原语比较

四、线程同步概念

 官方释义:线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不放回。同时其它线程为保证数据一致性,不能调用该功能。我的理解:就是保证不同线程方法调用共享数据时,要保证上一个线程执行完毕后,下一个线程再执行。保证共享数据一致性。同步的目的:避免数据混乱。解决与时间有关的错误。实际上不仅线程间需要同步,进程间、信号间等等都需要同步机制。数据混乱原因:1.资源共享2.调度随机3.线程间缺乏必要的同步机制。#下面主要就把讲这个。

五、线程同步——互斥锁(互斥量)

  1. 概念

    Linux中提供一把互斥锁mutex(也称为互斥量)。每个线程在对资源操作前都尝试加锁(没拿到锁就一直阻塞等待锁可用),成功加锁才能操作,操作结束后解锁。资源还是共享的,线程间也还是竞争的。但通过“锁”将资源访问变成互斥操作,但注意同一时间只能有一个线程持有该锁。建议锁,没有强制性。所有线程在访问公共数据前先拿锁再访问。但锁本身不具备强制性。

  2. 互斥锁实现

    使用互斥锁时尽可能访问共享数据前加锁,访问后立即解锁。互斥锁本质是结构体。可以看成整数。初值(pthread_mutex_init()后)为1.
    加锁: -- 阻塞线程。
    解锁: ++ 唤醒阻塞线程。实现步骤:pthread_mutex_t mylock;//定义互斥锁结构体,应声明为全局变量,放在全局位置pthread_mutex_init(&mylock,NULL);//初始化互斥锁,第二个参数默认NULL即可pthread_mutex_lock(&mylock);//加锁,线程阻塞,等待锁释放pthread_mutex_trylock(&mylock)//加锁,线程不阻塞,立即返回,线程不会阻塞pthread_mutex_unlock(&mylock);//解锁pthread_mutex_destroy(&mylock);//销毁锁1.pthread_mutex_tmutex锁结构体2.pthread_mutex_init()、pthread_mutex_destroy()man pthread_mutex_init(1)NAMEpthread_mutex_destroy, pthread_mutex_init — destroy and initialize a mutex(2)SYNOPSIS#include <pthread.h>int pthread_mutex_destroy(pthread_mutex_t *mutex);int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;(3)PARAMETER1.mutex:互斥锁结构体restrict关键字:只能引用定义的指针,不能使用另外赋值的指针。例:int *p=0xdddd;int * q=p;当定义函数int test(int * restrict x);时,参数x知道能传p,不能穿q。2.attr填NULL即可。(4)RETURN VALUEIf successful, the pthread_mutex_destroy() and pthread_mutex_init() functions shall return zero; otherwise, an error num‐ber shall be returned to indicate the error.3.pthread_mutex_lock()、pthread_mutex_unlock()man pthread_mutex_lock(1)NAMEpthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock — lock and unlock a mutex(2)SYNOPSIS#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);(3)RETURN VALUEIf successful, the pthread_mutex_lock(), pthread_mutex_trylock(), and pthread_mutex_unlock() functions shall return zero;otherwise, an error number shall be returned to indicate the error.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_mutex.c
    

六、死锁

两种情况:1.线程试图对同一个互斥量A加锁两次2.线程1 拥有 A锁,请求获取 B锁;线程2 拥有 B锁,请求获得A锁。DEMO:

七、读写锁

  1. 概念

    锁只有一把:以读方式给数据加锁——读锁。以写方式给数据加锁——写锁。读共享,写独占。
    写锁优先级高。【相较于互斥量而言,当读线程多的时候,提高访问效率】。特性如下图:
    

  2. 读写锁实现

    实现步骤:pthread_rwlock_t mylock;//定义读写锁全局变量pthread_rwlock_init(&mylock,NULL);//动态初始化读写锁pthread_rwlock_t mylock = PTHREAD_MUTEX_INITIALIZERpthread_rwlock_rdlock(&mylock);//加读锁,阻塞线程直到锁可用pthread_rwlock_tryrdlock(&mylock);//加读锁,不阻塞线程,直接返回结果pthread_rwlock_wrlock(&mylock);//加写锁,阻塞线线程直到锁可用pthread_rwlock_trywrlock(&mylock);//加写锁,不阻塞线程,直接返回结果pthread_rwlock_unlock(&mylock);//解锁pthread_rwlock_destroy(&mylock);//销毁读写锁函数解析:
    1.pthread_rwlock_init()、pthread_rwlock_destroy()man  pthread_rwlock_init(1)NAMEpthread_rwlock_destroy, pthread_rwlock_init — destroy and initialize a read-write lock object(2)SYNOPSIS#include <pthread.h>int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock,const pthread_rwlockattr_t *restrict attr);pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;(3)PARAMETER1.rwlock:互斥锁结构体restrict关键字:只能引用定义的指针,不能使用另外赋值的指针。例:int *p=0xdddd;int * q=p;当定义函数int test(int * restrict x);时,参数x知道能传p,不能穿q。2.attr填NULL即可。(4)RETURN VALUEIf successful, the pthread_rwlock_destroy() and pthread_rwlock_init() functions shall return zero;  otherwise,  an  errornumber shall be returned to indicate the error.2.pthread_rwlock_rdlock(), pthread_rwlock_tryrdlock()man  pthread_rwlock_rdlock(1)NAMEpthread_rwlock_rdlock, pthread_rwlock_tryrdlock — lock a read-write lock object for reading(2)SYNOPSIS#include <pthread.h>int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);    (3)RETURN VALUE成功:0失败:错误号。errno。3.pthread_rwlock_wrlock(),pthread_rwlock_trywrlock()(1)NAMEpthread_rwlock_trywrlock, pthread_rwlock_wrlock — lock a read-write lock object for writing(2)SYNOPSIS#include <pthread.h>int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);(3)RETURN VALUE成功:0失败:错误号。errno。4.pthread_rwlock_unlock()(1)NAMEpthread_rwlock_unlock — unlock a read-write lock object(2)SYNOPSIS#include <pthread.h>int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);(3)RETURN VALUEIf  successful,  the  pthread_rwlock_unlock() function shall return zero; otherwise, an error number shall be returned toindicate the error.DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/pthread_rwlock.c
    

八、条件变量

  1. 条件变量概念

    条件变量本身不是锁,但可以造成线程阻塞。
    通常与互斥锁配合使用(例如下面的生产者消费者模型)。主要函数如下:
    

    man 手册找不到下列函数。就用下面的安装命令安装。
    sudo apt-get install manpages-posix-dev1. pthread_cond_tpthread_cond_t cond;//条件变量结构体
    初始化条件变量:pthread_cond_init(&cond,NULL);                       //动态初始化pthread_cond_t cond = PTHREAD_COND_INITIALIZER;     //静态初始化2. pthread_cond_init()、pthread_cond_destroy()1)NAMEpthread_cond_destroy, pthread_cond_init — destroy and initialize condition variables2)SYNOPSIS#include <pthread.h>int pthread_cond_destroy(pthread_cond_t *cond);int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);pthread_cond_t cond = PTHREAD_COND_INITIALIZER;3)PARAMETERcond :条件变量结构体attr :NULL即可。4)RETURN VALUEIf successful, the pthread_cond_destroy() and pthread_cond_init() functions shall return zero; otherwise, an error numbershall be returned to indicate the error.3.pthread_cond_timedwait(), pthread_cond_wait()1)NAMEpthread_cond_timedwait, pthread_cond_wait — wait on a condition2)SYNOPSIS#include <pthread.h>int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);3)PARAMETERcond  :互斥量结构体mutex :初始化过的互斥锁结构体4)RETURN VALUEUpon  successful  completion, a value of zero shall be returned; otherwise, an error number shall be returned to indicatethe error.4. pthread_cond_broadcast(),//唤醒阻塞在条件变量上的 所有线程pthread_cond_signal()    //唤醒阻塞在条件变量上的 (至少)一个线程1)NAMEpthread_cond_broadcast, pthread_cond_signal — broadcast or signal a condition2)SYNOPSIS#include <pthread.h>int pthread_cond_broadcast(pthread_cond_t *cond);int pthread_cond_signal(pthread_cond_t *cond);3)PARAMETERcond:条件变量结构体4)RETURN VALUEIf successful, the pthread_cond_broadcast() and pthread_cond_signal() functions shall return zero;  otherwise,  an  errornumber shall be returned to indicate the error.DEMO:详见 八、生产者与消费者
    
  2. wait和timewait详解

九、生产者消费者模型(条件变量实现)

  1. 基础

  2. DEMO

    源码连接

十、信号量

  1. 基础

    信号量和互斥锁(1)类似,只是互斥锁最多只允许一个线程访问共享数据,而信号量(N)可以是多个线程访问。sem_t sem;//定义类型
    sem_wait(); //一次调用,做一次-- 操作,当信号量的值为 0 时,再次 -- 会阻塞。(对比 pthread_mutex_lock)
    sem_post();//一次调用,做一次++ 操作,当信号量的值为 N 时,再次 ++ 就会阻塞。(对比pthread_mutex_unlock)
    
  2. 涉及函数

    1.sem_t sem;//定义类型2.sem_init()man sem_init1)NAMEsem_init - initialize an unnamed semaphore2)SYNOPSIS#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);Link with -pthread.3)PARAMETERsem:信号量pshared :0 线程同步1 进程同步value :N值。信号量值。 (指定同时访问的线程数)4)RETURN VALUEsem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.3.sem_destroy()1)NAMEsem_destroy - destroy an unnamed semaphore2)SYNOPSIS#include <semaphore.h>int sem_destroy(sem_t *sem);Link with -pthread.3)RETURN VALUEsem_destroy() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.4.sem_wait(),sem_timedwait() //(对比 pthread_mutex_lock)man sem_wait1)NAMEsem_wait, sem_timedwait, sem_trywait - lock a semaphore2)SYNOPSIS#include <semaphore.h>int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);Link with -pthread.3)PARAMETERabs_timeout :采用的是绝对时间。和普通的定时不同。例:定时1秒time_t cur = time(NULL);//获取当前时间struct timespect t;//定义时间结构体变量t.tv_sec = cur+1;//定时1s.t.tv_nsec = t.tv_sec +100;sem_timewait(&sem,&t);//应用传参4)RETURN VALUEAll of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is  returned,  anderrno is set to indicate the error.5.sem_post()  //(对比pthread_mutex_unlock)man sem_post1)NAMEsem_post - unlock a semaphore2)SYNOPSIS#include <semaphore.h>int sem_post(sem_t *sem);Link with -pthread.3)RETURN VALUEsem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is setto indicate the error.
  3. 利用信号量实现生产者消费者模型

    DEMO:https://github.com/Panor520/LinuxCode/tree/master/thread/sem_produce_consumer.cDEMO配合下图看。
    

十一、线程池

  1. 基础概念

     epoll 实现 client 端和 server 端的连接。线程池 实现 server 端高效处理和客户端连接的操作。线程池的实现利用 条件变量 和 锁 机制。
    
  2. 实现
    DEMO还没来的及写,自行百度

Linux系统编程——线程相关推荐

  1. Linux系统编程——线程私有数据

    在多线程程序中.常常要用全局变量来实现多个函数间的数据共享.因为数据空间是共享的,因此全局变量也为全部线程共同拥有. 測试代码例如以下: #include <stdio.h> #inclu ...

  2. Linux系统编程——线程(1)

    目录 线程概要 Linux内核线程实现原理 线程的共享/不共享资源 线程优缺点 线程控制原语 pthread_self pthread_create pthread_exit pthread_join ...

  3. Linux系统编程——线程池

    http://blog.csdn.net/tennysonsky/article/details/46490099# 线程池基本原理 在传统服务器结构中,常是有一个总的监听线程监听有没有新的用户连接服 ...

  4. 入门Linux系统编程--网络编程

    文章目录 一.网络编程 1.socket服务端代码实现(无连接客户端) 6.socket服务端代码实现(连接客户端) 7.socket客户端代码实现 8.实现双方聊天 9.多方消息收发 二.往期文章 ...

  5. Linux系统编程之进程与线程控制原语对比

    Linux系统编程之进程与线程控制原语对比 进程 线程 fork pthread_create exit pthread_exit wait pthread_join kill pthread_can ...

  6. linux线程并不真正并行,Linux系统编程学习札记(十二)线程1

    Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...

  7. Linux系统编程(九)线程同步

    Linux系统编程(九)线程同步 一.什么是线程同步? 二.互斥量 三.条件变量 pthread_cond_wait函数 pthread_cond_signal函数 生产者和消费者模型 一.什么是线程 ...

  8. Linux系统编程(八)线程

    Linux系统编程(八)线程 一.什么是线程? 二.Linux内核线程实现原理 线程共享资源 线程非共享资源 线程优缺点 线程控制原语 一.什么是线程? LWP:light weight proces ...

  9. 【Linux | 系统编程】Linux系统编程(文件、进程线程、进程间通信)

    文章目录 Linux系统编程 文件IO open/close函数 read/write函数 文件描述符 阻塞.非阻塞 fcntl函数 lseek函数 传入传出参数 文件系统 文件存储 文件操作 sta ...

最新文章

  1. 编码中统一更该变量的快捷键_流媒体的7种方式使您成为更好的编码器
  2. python3 xml 取标签显示内容_如何应用“XML+XSLT”技术分离Web表示层数据和样式
  3. Mac下文件的编码及修改编码
  4. C++学习笔记-----存在多态调用时,为基类定义虚析构函数
  5. onclick 传参,用转义符进行转义。
  6. 【图像处理】——特征匹配(SIFT特征检测器+FLANN特征匹配方法+KNN近邻最优匹配筛选)——cv.xfeatures2d.SIFT_create()sift.detectAndCompute
  7. Theano3.2-练习之数据集及目标函数介绍
  8. Windows phone7 开发-Zune software is not launched 【转】
  9. C语言 最大公约数和最小公倍数计算
  10. 【华为云技术分享】Linux内核的分布式编译(2)
  11. 算法 Tricks(六)— if 条件分支的简化
  12. mac使用代理后出现502
  13. ictclas4j java_ictclas4j 分词工具包 安装流程
  14. 快速乘-在乘法溢出的边缘疯狂试探
  15. 七款简单易用的项目管理平台
  16. L1-079 天梯赛的善良 - java
  17. c语言程序设计理论考试,《C语言程序设计》理论试题库-程序题100例
  18. 射频器件厂商RFMD与TriQuint达成合并协议
  19. 快手2020校园招聘秋招笔试--工程C试卷 (编程题题解全)
  20. Python3,5行代码,制作Gif动图,太简单了。

热门文章

  1. VMS Software, Inc.
  2. 王川:一年读五百本书,让你每天高潮迭起
  3. 突发!大连理工大学研三学生自杀,遗书曝光,研究生的压力应该谁来化解?...
  4. 【STM32F042】ADC卡死,ADC一直为0,ADC配置的坑
  5. Excel日记:L24-用Left函数提取表格中的文字资料
  6. 两种方法扫二维码下载APP,获取IPA安装包
  7. anydesk 远程控制
  8. 使用RustDesk或者AnyDesk的TCP隧道实现Codesys系列PLC的远程调试和下载
  9. Java简单代码验证三门问题
  10. 五轴数控转台_有人说先学会三轴,再去搞四轴、五轴加工中心,这几种有何区别?...