0%

CAS(Compare And Set)来降低读写锁冲突。常见的版本通过版本比较来实现乐观锁,当然也很简单新增version 字段来保证自己本次操作是独立的,操作完并更新version得到new_version,当并发时候别人拿到之前version则操作失败

当发生并发时候,Client-1、Client-2、Client-3,获取到的 goods_number 都为10,version 都为 0,当Client -1~3任意一个用户操作,则version 将会增加1,这样一来其他人就会更新失败 。

exit()函数定义在stdlib.h中,而_exit()定义在unistd.h中,
注:exit()就是退出,传入的参数是程序退出时的状态码,0表示正常退出,其他表示非正常退出,一般都用-1或者1,标准C里有EXIT_SUCCESS和EXIT_FAILURE两个宏,用exit(EXIT_SUCCESS);

_exit()函数的作用最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit() 函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。

exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是”清理I/O缓冲”。

exit()在结束调用它的进程之前,要进行如下步骤:

1.调用atexit()注册的函数(出口函数);按ATEXIT注册时相反的顺序调用所有由它注册的函数,这使得我们可以指定在程序终止时执行自己的清理动作.例如,保存程序状态信息于某个文件,解开对共享数据库上的锁等.

2.cleanup();关闭所有打开的流,这将导致写所有被缓冲的输出,删除用TMPFILE函数建立的所有临时文件.

3.最后调用_exit()函数终止进程。

_exit做3件事(man):

1,Any open file descriptors belonging to the process are closed

2,any children of the process are inherited by process 1, init

3,the process’s parent is sent a SIGCHLD signal

exit执行完清理工作后就调用_exit来终止进程。

  1. Go 语言没有类和继承的概念,通过接口(interface)的概念来实现多态性

  2. 函数是 Go 语言中的基本构件

  3. Go 语言使用静态类型,作为强类型语言,隐式的类型转换是不被允许的

  4. Go 不需要依赖任何其它文件,它只需要一个单独的静态文件,这样你也不会像使用其它语言一样在各种不同版本的依赖文件之间混淆。

  5. for的用法
    for key, value := range oldMap {
    newMap[key] = value
    }

  6. Go的 defer 语句用于预设一个函数调用(即推迟执行函数),该函数会在执行 defer 的函数返回之前立即执行。典型的例子就是解锁互斥和关闭文件。

  7. append连接两个数组的用法
    x := []int{1,2,3}
    y := []int{4,5,6}
    x = append(x, y…)
    fmt.Println(x)
    如果没有 …,它就会由于类型错误而无法编译,因为 y 不是 int 类型的

  8. 变量声明的两种写法
    a := 1
    var a = 1
    个人觉得下面这个更好,对于习惯更多编程语言的人来说更可读,而且全局定义只能用下面这种方式

  9. 反单引号可以跨行,并且引号内的所有内容 都会直接输出,包括转义宇符和空格缩进等。 而双引号则不能换行, 并且会解析转义字符。

  10. 函数作为类型可以类比c#委托,用于简化代码

  11. Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量?
    Golang中Goroutine 可以通过 Channel 进行安全读写共享变量。

  12. 无缓冲 Chan 的发送和接收是否同步?
    ch := make(chan int) 无缓冲的channel由于没有缓冲发送和接收需要同步。
    ch := make(chan int, 2) 有缓冲channel不要求发送和接收操作同步。
    channel无缓冲时,发送阻塞直到数据被接收,接收阻塞直到读到数据。
    channel有缓冲时,当缓冲满时发送阻塞,当缓冲空时接收阻塞。

  13. Golang 中常用的并发模型有三种:
    通过channel通知实现并发控制
    通过sync包中的WaitGroup实现并发控制
    在Go 1.7 以后引进的强大的Context上下文,实现并发控制

  14. 通过大小写决定数据类型是公有还是私有

  15. 用工厂方法实现结构体的构造函数

  16. nil slice 和 空 slice 的处理是不一致.
    通常错误的用法,会报数组越界的错误,因为只是声明了slice,却没有给实例化的对象。
    var slice []int
    slice[1] = 0
    此时slice的值是nil,这种情况可以用于需要返回slice的函数,当函数出现异常的时候,保证函数依然会有nil的返回值。
    empty slice 是指slice不为nil,但是slice没有值,slice的底层的空间是空的,此时的定义如下:
    slice := make([]int,0)
    slice := []int{}
    当我们查询或者处理一个空的列表的时候,这非常有用,它会告诉我们返回的是一个列表,但是列表内没有任何值。

http断点续传工作原理

Etag 由服务器端生成,客户端通过 If-Range 条件判断请求来验证资源是否修改。请求一个文件的流程如下:

第一次请求:

客户端发起 HTTP GET 请求一个文件。

服务器处理请求,返回文件内容以及相应的 Header,其中包括 Etag(例如:627-4d648041f6b80)(假设服务器支持 Etag 生成并已开启了 Etag)状态码为 200。

第二次请求(断点续传):

客户端发起 HTTP GET 请求一个文件,同时发送 If-Range(该头的内容就是第一次请求时服务器返回的 Etag:627-4d648041f6b80)。

服务器判断接收到的 Etag 和计算出来的 Etag 是否匹配,如果匹配,那么响应的状态码为 206;否则,状态码为 200。

HTTPS简介

HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据

1. 客户端发起HTTPS请求

这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。

2. 服务端的配置

采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。

3. 传送证书

这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

4. 客户端解析证书

这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

5. 传送加密信息

这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

6. 服务段解密信息

服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

7. 传输加密后的信息

这部分信息是服务段用私钥加密后的信息,可以在客户端被还原

8. 客户端解密信息

客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也束手无策。