mirror of
https://gitee.com/johng/gf.git
synced 2024-12-04 05:07:44 +08:00
commit
d41cc7c3b6
@ -15,6 +15,7 @@
|
||||
|潘兄|wechat|¥100.00
|
||||
|Fly的狐狸|wechat|¥100.00
|
||||
|土豆相公|alipay|¥66.60
|
||||
|蔡蔡|wechat|¥666.00
|
||||
|上海金保证网络科技|bank|¥2000.00
|
||||
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
package garray
|
||||
|
||||
|
||||
type apiSliceInterface interface {
|
||||
Slice() []interface{}
|
||||
}
|
||||
|
@ -29,21 +29,33 @@ func NewBool(value...bool) *Bool {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for bool type.
|
||||
func (t *Bool) Clone() *Bool {
|
||||
return NewBool(t.Val())
|
||||
func (v *Bool) Clone() *Bool {
|
||||
return NewBool(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Bool) Set(value bool) (old bool) {
|
||||
func (v *Bool) Set(value bool) (old bool) {
|
||||
if value {
|
||||
old = atomic.SwapInt32(&t.value, 1) == 1
|
||||
old = atomic.SwapInt32(&v.value, 1) == 1
|
||||
} else {
|
||||
old = atomic.SwapInt32(&t.value, 0) == 1
|
||||
old = atomic.SwapInt32(&v.value, 0) == 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.valueue.
|
||||
func (t *Bool) Val() bool {
|
||||
return atomic.LoadInt32(&t.value) > 0
|
||||
func (v *Bool) Val() bool {
|
||||
return atomic.LoadInt32(&v.value) > 0
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Bool) Cas(old, new bool) bool {
|
||||
var oldInt32, newInt32 int32
|
||||
if old {
|
||||
oldInt32 = 1
|
||||
}
|
||||
if new {
|
||||
newInt32 = 1
|
||||
}
|
||||
return atomic.CompareAndSwapInt32(&v.value, oldInt32, newInt32)
|
||||
}
|
@ -26,21 +26,26 @@ func NewByte(value...byte) *Byte {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for byte type.
|
||||
func (t *Byte) Clone() *Byte {
|
||||
return NewByte(t.Val())
|
||||
func (v *Byte) Clone() *Byte {
|
||||
return NewByte(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Byte) Set(value byte) (old byte) {
|
||||
return byte(atomic.SwapInt32(&t.value, int32(value)))
|
||||
func (v *Byte) Set(value byte) (old byte) {
|
||||
return byte(atomic.SwapInt32(&v.value, int32(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Byte) Val() byte {
|
||||
return byte(atomic.LoadInt32(&t.value))
|
||||
func (v *Byte) Val() byte {
|
||||
return byte(atomic.LoadInt32(&v.value))
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Byte) Add(delta int) (new byte) {
|
||||
return byte(atomic.AddInt32(&t.value, int32(delta)))
|
||||
func (v *Byte) Add(delta byte) (new byte) {
|
||||
return byte(atomic.AddInt32(&v.value, int32(delta)))
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Byte) Cas(old, new byte) bool {
|
||||
return atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))
|
||||
}
|
||||
|
@ -23,21 +23,21 @@ func NewBytes(value...[]byte) *Bytes {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for []byte type.
|
||||
func (t *Bytes) Clone() *Bytes {
|
||||
return NewBytes(t.Val())
|
||||
func (v *Bytes) Clone() *Bytes {
|
||||
return NewBytes(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
// Note: The parameter <value> cannot be nil.
|
||||
func (t *Bytes) Set(value []byte) (old []byte) {
|
||||
old = t.Val()
|
||||
t.value.Store(value)
|
||||
func (v *Bytes) Set(value []byte) (old []byte) {
|
||||
old = v.Val()
|
||||
v.value.Store(value)
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Bytes) Val() []byte {
|
||||
if s := t.value.Load(); s != nil {
|
||||
func (v *Bytes) Val() []byte {
|
||||
if s := v.value.Load(); s != nil {
|
||||
return s.([]byte)
|
||||
}
|
||||
return nil
|
||||
|
@ -28,27 +28,27 @@ func NewFloat32(value...float32) *Float32 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for float32 type.
|
||||
func (t *Float32) Clone() *Float32 {
|
||||
return NewFloat32(t.Val())
|
||||
func (v *Float32) Clone() *Float32 {
|
||||
return NewFloat32(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Float32) Set(value float32) (old float32) {
|
||||
return math.Float32frombits(atomic.SwapUint32(&t.value, math.Float32bits(value)))
|
||||
func (v *Float32) Set(value float32) (old float32) {
|
||||
return math.Float32frombits(atomic.SwapUint32(&v.value, math.Float32bits(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Float32) Val() float32 {
|
||||
return math.Float32frombits(atomic.LoadUint32(&t.value))
|
||||
func (v *Float32) Val() float32 {
|
||||
return math.Float32frombits(atomic.LoadUint32(&v.value))
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Float32) Add(delta float32) (new float32) {
|
||||
func (v *Float32) Add(delta float32) (new float32) {
|
||||
for {
|
||||
old := math.Float32frombits(t.value)
|
||||
old := math.Float32frombits(v.value)
|
||||
new = old + delta
|
||||
if atomic.CompareAndSwapUint32(
|
||||
(*uint32)(unsafe.Pointer(&t.value)),
|
||||
(*uint32)(unsafe.Pointer(&v.value)),
|
||||
math.Float32bits(old),
|
||||
math.Float32bits(new),
|
||||
) {
|
||||
@ -56,4 +56,9 @@ func (t *Float32) Add(delta float32) (new float32) {
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float32) Cas(old, new float32) bool {
|
||||
return atomic.CompareAndSwapUint32(&v.value, uint32(old), uint32(new))
|
||||
}
|
||||
|
@ -28,27 +28,27 @@ func NewFloat64(value...float64) *Float64 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for float64 type.
|
||||
func (t *Float64) Clone() *Float64 {
|
||||
return NewFloat64(t.Val())
|
||||
func (v *Float64) Clone() *Float64 {
|
||||
return NewFloat64(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Float64) Set(value float64) (old float64) {
|
||||
return math.Float64frombits(atomic.SwapUint64(&t.value, math.Float64bits(value)))
|
||||
func (v *Float64) Set(value float64) (old float64) {
|
||||
return math.Float64frombits(atomic.SwapUint64(&v.value, math.Float64bits(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Float64) Val() float64 {
|
||||
return math.Float64frombits(atomic.LoadUint64(&t.value))
|
||||
func (v *Float64) Val() float64 {
|
||||
return math.Float64frombits(atomic.LoadUint64(&v.value))
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Float64) Add(delta float64) (new float64) {
|
||||
func (v *Float64) Add(delta float64) (new float64) {
|
||||
for {
|
||||
old := math.Float64frombits(t.value)
|
||||
old := math.Float64frombits(v.value)
|
||||
new = old + delta
|
||||
if atomic.CompareAndSwapUint64(
|
||||
(*uint64)(unsafe.Pointer(&t.value)),
|
||||
(*uint64)(unsafe.Pointer(&v.value)),
|
||||
math.Float64bits(old),
|
||||
math.Float64bits(new),
|
||||
) {
|
||||
@ -57,3 +57,8 @@ func (t *Float64) Add(delta float64) (new float64) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float64) Cas(old, new float64) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
|
||||
}
|
||||
|
@ -26,21 +26,26 @@ func NewInt(value...int) *Int {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for int type.
|
||||
func (t *Int) Clone() *Int {
|
||||
return NewInt(t.Val())
|
||||
func (v *Int) Clone() *Int {
|
||||
return NewInt(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Int) Set(value int) (old int) {
|
||||
return int(atomic.SwapInt64(&t.value, int64(value)))
|
||||
func (v *Int) Set(value int) (old int) {
|
||||
return int(atomic.SwapInt64(&v.value, int64(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Int) Val() int {
|
||||
return int(atomic.LoadInt64(&t.value))
|
||||
func (v *Int) Val() int {
|
||||
return int(atomic.LoadInt64(&v.value))
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Int) Add(delta int) (new int) {
|
||||
return int(atomic.AddInt64(&t.value, int64(delta)))
|
||||
func (v *Int) Add(delta int) (new int) {
|
||||
return int(atomic.AddInt64(&v.value, int64(delta)))
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int) Cas(old, new int) bool {
|
||||
return atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))
|
||||
}
|
@ -26,21 +26,26 @@ func NewInt32(value...int32) *Int32 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for int32 type.
|
||||
func (t *Int32) Clone() *Int32 {
|
||||
return NewInt32(t.Val())
|
||||
func (v *Int32) Clone() *Int32 {
|
||||
return NewInt32(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Int32) Set(value int32) (old int32) {
|
||||
return atomic.SwapInt32(&t.value, value)
|
||||
func (v *Int32) Set(value int32) (old int32) {
|
||||
return atomic.SwapInt32(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Int32) Val() int32 {
|
||||
return atomic.LoadInt32(&t.value)
|
||||
func (v *Int32) Val() int32 {
|
||||
return atomic.LoadInt32(&v.value)
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Int32) Add(delta int32) (new int32) {
|
||||
return atomic.AddInt32(&t.value, delta)
|
||||
func (v *Int32) Add(delta int32) (new int32) {
|
||||
return atomic.AddInt32(&v.value, delta)
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int32) Cas(old, new int32) bool {
|
||||
return atomic.CompareAndSwapInt32(&v.value, old, new)
|
||||
}
|
@ -26,21 +26,26 @@ func NewInt64(value...int64) *Int64 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for int64 type.
|
||||
func (t *Int64) Clone() *Int64 {
|
||||
return NewInt64(t.Val())
|
||||
func (v *Int64) Clone() *Int64 {
|
||||
return NewInt64(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Int64) Set(value int64) (old int64) {
|
||||
return atomic.SwapInt64(&t.value, value)
|
||||
func (v *Int64) Set(value int64) (old int64) {
|
||||
return atomic.SwapInt64(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Int64) Val() int64 {
|
||||
return atomic.LoadInt64(&t.value)
|
||||
func (v *Int64) Val() int64 {
|
||||
return atomic.LoadInt64(&v.value)
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Int64) Add(delta int64) int64 {
|
||||
return atomic.AddInt64(&t.value, delta)
|
||||
func (v *Int64) Add(delta int64) int64 {
|
||||
return atomic.AddInt64(&v.value, delta)
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int64) Cas(old, new int64) bool {
|
||||
return atomic.CompareAndSwapInt64(&v.value, old, new)
|
||||
}
|
@ -25,19 +25,19 @@ func NewInterface(value...interface{}) *Interface {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for interface{} type.
|
||||
func (t *Interface) Clone() *Interface {
|
||||
return NewInterface(t.Val())
|
||||
func (v *Interface) Clone() *Interface {
|
||||
return NewInterface(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
// Note: The parameter <value> cannot be nil.
|
||||
func (t *Interface) Set(value interface{}) (old interface{}) {
|
||||
old = t.Val()
|
||||
t.value.Store(value)
|
||||
func (v *Interface) Set(value interface{}) (old interface{}) {
|
||||
old = v.Val()
|
||||
v.value.Store(value)
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Interface) Val() interface{} {
|
||||
return t.value.Load()
|
||||
func (v *Interface) Val() interface{} {
|
||||
return v.value.Load()
|
||||
}
|
@ -25,20 +25,20 @@ func NewString(value...string) *String {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for string type.
|
||||
func (t *String) Clone() *String {
|
||||
return NewString(t.Val())
|
||||
func (v *String) Clone() *String {
|
||||
return NewString(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *String) Set(value string) (old string) {
|
||||
old = t.Val()
|
||||
t.value.Store(value)
|
||||
func (v *String) Set(value string) (old string) {
|
||||
old = v.Val()
|
||||
v.value.Store(value)
|
||||
return
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *String) Val() string {
|
||||
s := t.value.Load()
|
||||
func (v *String) Val() string {
|
||||
s := v.value.Load()
|
||||
if s != nil {
|
||||
return s.(string)
|
||||
}
|
||||
|
@ -26,21 +26,26 @@ func NewUint(value...uint) *Uint {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for uint type.
|
||||
func (t *Uint) Clone() *Uint {
|
||||
return NewUint(t.Val())
|
||||
func (v *Uint) Clone() *Uint {
|
||||
return NewUint(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Uint) Set(value uint) (old uint) {
|
||||
return uint(atomic.SwapUint64(&t.value, uint64(value)))
|
||||
func (v *Uint) Set(value uint) (old uint) {
|
||||
return uint(atomic.SwapUint64(&v.value, uint64(value)))
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Uint) Val() uint {
|
||||
return uint(atomic.LoadUint64(&t.value))
|
||||
func (v *Uint) Val() uint {
|
||||
return uint(atomic.LoadUint64(&v.value))
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Uint) Add(delta uint) (new uint) {
|
||||
return uint(atomic.AddUint64(&t.value, uint64(delta)))
|
||||
func (v *Uint) Add(delta uint) (new uint) {
|
||||
return uint(atomic.AddUint64(&v.value, uint64(delta)))
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint) Cas(old, new uint) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
|
||||
}
|
@ -26,21 +26,26 @@ func NewUint32(value...uint32) *Uint32 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for uint32 type.
|
||||
func (t *Uint32) Clone() *Uint32 {
|
||||
return NewUint32(t.Val())
|
||||
func (v *Uint32) Clone() *Uint32 {
|
||||
return NewUint32(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Uint32) Set(value uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&t.value, value)
|
||||
func (v *Uint32) Set(value uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Uint32) Val() uint32 {
|
||||
return atomic.LoadUint32(&t.value)
|
||||
func (v *Uint32) Val() uint32 {
|
||||
return atomic.LoadUint32(&v.value)
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Uint32) Add(delta uint32) (new uint32) {
|
||||
return atomic.AddUint32(&t.value, delta)
|
||||
func (v *Uint32) Add(delta uint32) (new uint32) {
|
||||
return atomic.AddUint32(&v.value, delta)
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint32) Cas(old, new uint32) bool {
|
||||
return atomic.CompareAndSwapUint32(&v.value, old, new)
|
||||
}
|
@ -26,21 +26,26 @@ func NewUint64(value...uint64) *Uint64 {
|
||||
}
|
||||
|
||||
// Clone clones and returns a new concurrent-safe object for uint64 type.
|
||||
func (t *Uint64) Clone() *Uint64 {
|
||||
return NewUint64(t.Val())
|
||||
func (v *Uint64) Clone() *Uint64 {
|
||||
return NewUint64(v.Val())
|
||||
}
|
||||
|
||||
// Set atomically stores <value> into t.value and returns the previous value of t.value.
|
||||
func (t *Uint64) Set(value uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&t.value, value)
|
||||
func (v *Uint64) Set(value uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&v.value, value)
|
||||
}
|
||||
|
||||
// Val atomically loads t.value.
|
||||
func (t *Uint64) Val() uint64 {
|
||||
return atomic.LoadUint64(&t.value)
|
||||
func (v *Uint64) Val() uint64 {
|
||||
return atomic.LoadUint64(&v.value)
|
||||
}
|
||||
|
||||
// Add atomically adds <delta> to t.value and returns the new value.
|
||||
func (t *Uint64) Add(delta uint64) (new uint64) {
|
||||
return atomic.AddUint64(&t.value, delta)
|
||||
func (v *Uint64) Add(delta uint64) (new uint64) {
|
||||
return atomic.AddUint64(&v.value, delta)
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint64) Cas(old, new uint64) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, old, new)
|
||||
}
|
@ -18,8 +18,18 @@ const (
|
||||
ivDefValue = "I Love Go Frame!"
|
||||
)
|
||||
|
||||
// AES加密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数
|
||||
// Encrypt is alias of EncryptCBC.
|
||||
func Encrypt(plainText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
return EncryptCBC(plainText, key, iv...)
|
||||
}
|
||||
|
||||
// Decrypt is alias of DecryptCBC.
|
||||
func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
return DecryptCBC(cipherText, key, iv...)
|
||||
}
|
||||
|
||||
// AES加密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数。
|
||||
func EncryptCBC(plainText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -40,7 +50,7 @@ func Encrypt(plainText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
// AES解密, 使用CBC模式,注意key必须为16/24/32位长度,iv初始化向量为非必需参数
|
||||
func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
func DecryptCBC(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -62,9 +72,9 @@ func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
|
||||
plainText := make([]byte, len(cipherText))
|
||||
blockModel.CryptBlocks(plainText, cipherText)
|
||||
plainText, e := PKCS5UnPadding(plainText, blockSize)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
@ -98,3 +108,58 @@ func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
|
||||
|
||||
return src[:(length - unpadding)], nil
|
||||
}
|
||||
|
||||
// AES加密, 使用CFB模式。
|
||||
// 注意key必须为16/24/32位长度,padding返回补位长度,iv初始化向量为非必需参数。
|
||||
func EncryptCFB(plainText []byte, key []byte, padding *int, iv ...[]byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
plainText, *padding = ZeroPadding(plainText, blockSize) //补位0
|
||||
ivValue := ([]byte)(nil)
|
||||
if len(iv) > 0 {
|
||||
ivValue = iv[0]
|
||||
} else {
|
||||
ivValue = []byte(ivDefValue)
|
||||
}
|
||||
stream := cipher.NewCFBEncrypter(block, ivValue)
|
||||
cipherText := make([]byte, len(plainText))
|
||||
stream.XORKeyStream(cipherText, plainText)
|
||||
return cipherText, nil
|
||||
}
|
||||
|
||||
// AES解密, 使用CFB模式。
|
||||
// 注意key必须为16/24/32位长度,unpadding为去补位长度,iv初始化向量为非必需参数。
|
||||
func DecryptCFB(cipherText []byte, key []byte, unpadding int, iv ...[]byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(cipherText) < aes.BlockSize {
|
||||
return nil, errors.New("cipherText too short")
|
||||
}
|
||||
ivValue := ([]byte)(nil)
|
||||
if len(iv) > 0 {
|
||||
ivValue = iv[0]
|
||||
} else {
|
||||
ivValue = []byte(ivDefValue)
|
||||
}
|
||||
stream := cipher.NewCFBDecrypter(block, ivValue)
|
||||
plainText := make([]byte, len(cipherText))
|
||||
stream.XORKeyStream(plainText, cipherText)
|
||||
plainText = ZeroUnPadding(plainText, unpadding) //去补位0
|
||||
return plainText, nil
|
||||
}
|
||||
|
||||
func ZeroPadding(ciphertext []byte, blockSize int) ([]byte, int) {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(0)}, padding)
|
||||
return append(ciphertext, padtext...), padding
|
||||
}
|
||||
|
||||
func ZeroUnPadding(plaintext []byte, unpadding int) []byte {
|
||||
length := len(plaintext)
|
||||
return plaintext[:(length - unpadding)]
|
||||
}
|
@ -32,6 +32,10 @@ var (
|
||||
keys = []byte("12345678912345678912345678912346")
|
||||
key_err = []byte("1234")
|
||||
key_32_err = []byte("1234567891234567891234567891234 ")
|
||||
|
||||
// cfb模式blockSize补位长度, add by zseeker
|
||||
padding_size = 16 - len(content)
|
||||
content_16_cfb, _ = gbase64.Decode("oSmget3aBDT1nJnBp8u6kA==")
|
||||
)
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
@ -125,3 +129,21 @@ func TestPKCS5UnPaddingErr(t *testing.T) {
|
||||
gtest.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestEncryptCFB(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var padding int = 0
|
||||
data, err := gaes.EncryptCFB(content, key_16, &padding, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(padding, padding_size)
|
||||
gtest.Assert(data, []byte(content_16_cfb))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDecryptCFB(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
decrypt, err := gaes.DecryptCFB([]byte(content_16_cfb), key_16, padding_size, iv)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(decrypt, content)
|
||||
})
|
||||
}
|
||||
|
@ -4,11 +4,12 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package mutex provides switch for sync.Mutex for concurrent safe feature.
|
||||
// Package mutex provides switch of concurrent safe feature for sync.Mutex.
|
||||
package mutex
|
||||
|
||||
import "sync"
|
||||
|
||||
// Mutex is a sync.Mutex with a switch of concurrent safe feature.
|
||||
type Mutex struct {
|
||||
sync.Mutex
|
||||
safe bool
|
||||
|
@ -4,11 +4,12 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package rwmutex provides switch for sync.RWMutex for concurrent safe feature.
|
||||
// Package rwmutex provides switch of concurrent safe feature for sync.RWMutex.
|
||||
package rwmutex
|
||||
|
||||
import "sync"
|
||||
|
||||
// RWMutex is a sync.RWMutex with a switch of concurrent safe feature.
|
||||
type RWMutex struct {
|
||||
sync.RWMutex
|
||||
safe bool
|
||||
|
@ -4,7 +4,5 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// Package ghttp provides a powerful http server and a simple client.
|
||||
//
|
||||
// ghttp是GF框架的核心模块,实现了一个强大的Web Server,并提供了一个简便的HTTP客户端。
|
||||
// Package ghttp provides powerful http server and simple client implements.
|
||||
package ghttp
|
||||
|
@ -37,8 +37,8 @@ func init() {
|
||||
}
|
||||
|
||||
// SetPath sets the directory path for file logging.
|
||||
func SetPath(path string) {
|
||||
logger.SetPath(path)
|
||||
func SetPath(path string) error {
|
||||
return logger.SetPath(path)
|
||||
}
|
||||
|
||||
// GetPath returns the logging directory path for file logging.
|
||||
@ -89,7 +89,7 @@ func SetAsync(enabled bool) {
|
||||
logger.SetAsync(enabled)
|
||||
}
|
||||
|
||||
// SetStdoutPrint sets whether ouptput the logging contents to stdout, which is false in default.
|
||||
// SetStdoutPrint sets whether ouptput the logging contents to stdout, which is true in default.
|
||||
func SetStdoutPrint(enabled bool) {
|
||||
logger.SetStdoutPrint(enabled)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@ -356,6 +357,10 @@ func (l *Logger) GetBacktrace(skip...int) string {
|
||||
// Find the true caller file path using custom skip.
|
||||
index := 1
|
||||
goRoot := runtime.GOROOT()
|
||||
if goRoot != "" {
|
||||
goRoot = strings.Replace(goRoot, "\\", "/", -1)
|
||||
goRoot = regexp.QuoteMeta(goRoot)
|
||||
}
|
||||
for i := from + customSkip + l.btSkip; i < 1000; i++ {
|
||||
if _, file, cline, ok := runtime.Caller(i); ok && len(file) > 2 {
|
||||
if (goRoot == "" || !gregex.IsMatchString("^" + goRoot, file)) && !gregex.IsMatchString(`<autogenerated>`, file) {
|
||||
|
@ -14,46 +14,46 @@ var (
|
||||
locker = New()
|
||||
)
|
||||
|
||||
// TryLock tries locking the <key> with write lock,
|
||||
// it returns true if success, or if there's a write/read lock the <key>,
|
||||
// TryLock tries locking the <key> with writing lock,
|
||||
// it returns true if success, or if there's a write/reading lock the <key>,
|
||||
// it returns false. The parameter <expire> specifies the max duration it locks.
|
||||
func TryLock(key string, expire...time.Duration) bool {
|
||||
return locker.TryLock(key, expire...)
|
||||
}
|
||||
|
||||
// Lock locks the <key> with write lock.
|
||||
// If there's a write/read lock the <key>,
|
||||
// Lock locks the <key> with writing lock.
|
||||
// If there's a write/reading lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func Lock(key string, expire...time.Duration) {
|
||||
locker.Lock(key, expire...)
|
||||
}
|
||||
|
||||
// Unlock unlocks the write lock of the <key>.
|
||||
// Unlock unlocks the writing lock of the <key>.
|
||||
func Unlock(key string) {
|
||||
locker.Unlock(key)
|
||||
}
|
||||
|
||||
// TryRLock tries locking the <key> with read lock.
|
||||
// It returns true if success, or if there's a write lock on <key>, it returns false.
|
||||
// TryRLock tries locking the <key> with reading lock.
|
||||
// It returns true if success, or if there's a writing lock on <key>, it returns false.
|
||||
func TryRLock(key string) bool {
|
||||
return locker.TryRLock(key)
|
||||
}
|
||||
|
||||
// RLock locks the <key> with read lock.
|
||||
// If there's a write lock on <key>,
|
||||
// it will blocks until the write lock is released.
|
||||
// RLock locks the <key> with reading lock.
|
||||
// If there's a writing lock on <key>,
|
||||
// it will blocks until the writing lock is released.
|
||||
func RLock(key string) {
|
||||
locker.RLock(key)
|
||||
}
|
||||
|
||||
// RUnlock unlocks the read lock of the <key>.
|
||||
// RUnlock unlocks the reading lock of the <key>.
|
||||
func RUnlock(key string) {
|
||||
locker.RUnlock(key)
|
||||
}
|
||||
|
||||
// TryLockFunc locks the <key> with write lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/read lock the <key>, it return false.
|
||||
// TryLockFunc locks the <key> with writing lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/reading lock the <key>, it return false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
@ -62,8 +62,8 @@ func TryLockFunc(key string, f func(), expire...time.Duration) bool {
|
||||
return locker.TryLockFunc(key, f, expire...)
|
||||
}
|
||||
|
||||
// TryRLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write lock the <key>, it returns false.
|
||||
// TryRLockFunc locks the <key> with reading lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a writing lock the <key>, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
@ -72,8 +72,8 @@ func TryRLockFunc(key string, f func()) bool {
|
||||
return locker.TryRLockFunc(key, f)
|
||||
}
|
||||
|
||||
// LockFunc locks the <key> with write lock and callback function <f>.
|
||||
// If there's a write/read lock the <key>,
|
||||
// LockFunc locks the <key> with writing lock and callback function <f>.
|
||||
// If there's a write/reading lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
@ -83,8 +83,8 @@ func LockFunc(key string, f func(), expire...time.Duration) {
|
||||
locker.LockFunc(key, f, expire...)
|
||||
}
|
||||
|
||||
// RLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// If there's a write lock the <key>,
|
||||
// RLockFunc locks the <key> with reading lock and callback function <f>.
|
||||
// If there's a writing lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
|
@ -25,50 +25,50 @@ func New() *Locker {
|
||||
}
|
||||
}
|
||||
|
||||
// TryLock tries locking the <key> with write lock,
|
||||
// it returns true if success, or if there's a write/read lock the <key>,
|
||||
// it returns false. The parameter <expire> specifies the max duration it locks.
|
||||
// TryLock tries locking the <key> with writing lock,
|
||||
// it returns true if success, or it returns false if there's a writing/reading lock the <key>.
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func (l *Locker) TryLock(key string, expire...time.Duration) bool {
|
||||
return l.doLock(key, l.getExpire(expire...), true)
|
||||
}
|
||||
|
||||
// Lock locks the <key> with write lock.
|
||||
// If there's a write/read lock the <key>,
|
||||
// Lock locks the <key> with writing lock.
|
||||
// If there's a write/reading lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func (l *Locker) Lock(key string, expire...time.Duration) {
|
||||
l.doLock(key, l.getExpire(expire...), false)
|
||||
}
|
||||
|
||||
// Unlock unlocks the write lock of the <key>.
|
||||
// Unlock unlocks the writing lock of the <key>.
|
||||
func (l *Locker) Unlock(key string) {
|
||||
if v := l.m.Get(key); v != nil {
|
||||
v.(*Mutex).Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// TryRLock tries locking the <key> with read lock.
|
||||
// It returns true if success, or if there's a write lock on <key>, it returns false.
|
||||
// TryRLock tries locking the <key> with reading lock.
|
||||
// It returns true if success, or if there's a writing lock on <key>, it returns false.
|
||||
func (l *Locker) TryRLock(key string) bool {
|
||||
return l.doRLock(key, true)
|
||||
}
|
||||
|
||||
// RLock locks the <key> with read lock.
|
||||
// If there's a write lock on <key>,
|
||||
// it will blocks until the write lock is released.
|
||||
// RLock locks the <key> with reading lock.
|
||||
// If there's a writing lock on <key>,
|
||||
// it will blocks until the writing lock is released.
|
||||
func (l *Locker) RLock(key string) {
|
||||
l.doRLock(key, false)
|
||||
}
|
||||
|
||||
// RUnlock unlocks the read lock of the <key>.
|
||||
// RUnlock unlocks the reading lock of the <key>.
|
||||
func (l *Locker) RUnlock(key string) {
|
||||
if v := l.m.Get(key); v != nil {
|
||||
v.(*Mutex).RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
// TryLockFunc locks the <key> with write lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/read lock the <key>, it return false.
|
||||
// TryLockFunc locks the <key> with writing lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write/reading lock the <key>, it return false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
@ -82,8 +82,8 @@ func (l *Locker) TryLockFunc(key string, f func(), expire...time.Duration) bool
|
||||
return false
|
||||
}
|
||||
|
||||
// TryRLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a write lock the <key>, it returns false.
|
||||
// TryRLockFunc locks the <key> with reading lock and callback function <f>.
|
||||
// It returns true if success, or else if there's a writing lock the <key>, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
//
|
||||
@ -97,8 +97,8 @@ func (l *Locker) TryRLockFunc(key string, f func()) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// LockFunc locks the <key> with write lock and callback function <f>.
|
||||
// If there's a write/read lock the <key>,
|
||||
// LockFunc locks the <key> with writing lock and callback function <f>.
|
||||
// If there's a write/reading lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
@ -110,8 +110,8 @@ func (l *Locker) LockFunc(key string, f func(), expire...time.Duration) {
|
||||
f()
|
||||
}
|
||||
|
||||
// RLockFunc locks the <key> with read lock and callback function <f>.
|
||||
// If there's a write lock the <key>,
|
||||
// RLockFunc locks the <key> with reading lock and callback function <f>.
|
||||
// If there's a writing lock the <key>,
|
||||
// it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
@ -137,8 +137,8 @@ func (l *Locker) getExpire(expire...time.Duration) time.Duration {
|
||||
// It returns true if success, or else returns false.
|
||||
//
|
||||
// The parameter <try> is true,
|
||||
// it returns false immediately if it fails getting the write lock.
|
||||
// If <true> is false, it blocks until it gets the write lock.
|
||||
// it returns false immediately if it fails getting the writing lock.
|
||||
// If <true> is false, it blocks until it gets the writing lock.
|
||||
//
|
||||
// The parameter <expire> specifies the max duration it locks.
|
||||
func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
|
||||
@ -164,8 +164,8 @@ func (l *Locker) doLock(key string, expire time.Duration, try bool) bool {
|
||||
// It returns true if success, or else returns false.
|
||||
//
|
||||
// The parameter <try> is true,
|
||||
// it returns false immediately if it fails getting the read lock.
|
||||
// If <true> is false, it blocks until it gets the read lock.
|
||||
// it returns false immediately if it fails getting the reading lock.
|
||||
// If <true> is false, it blocks until it gets the reading lock.
|
||||
func (l *Locker) doRLock(key string, try bool) bool {
|
||||
mu := l.getOrNewMutex(key)
|
||||
ok := true
|
||||
|
@ -8,103 +8,130 @@ package gmlock
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// The high level Mutex.
|
||||
// The high level RWMutex.
|
||||
// It wraps the sync.RWMutex to implements more rich features.
|
||||
type Mutex struct {
|
||||
mu sync.RWMutex
|
||||
wid *gtype.Int64 // Unique id, used for multiple safely Unlock.
|
||||
rcount *gtype.Int // Reading locks count.
|
||||
wcount *gtype.Int // Writing locks count.
|
||||
mu sync.RWMutex
|
||||
wid *gtype.Int64 // Unique id, used for multiple and safe logic Unlock.
|
||||
locking *gtype.Bool // Locking mark for atomic operation for *Lock and Try*Lock functions.
|
||||
// There must be only one locking operation at the same time for concurrent safe purpose.
|
||||
state *gtype.Int32 // Locking state:
|
||||
// 0: writing lock false;
|
||||
// -1: writing lock true;
|
||||
// >=1: reading lock;
|
||||
}
|
||||
|
||||
// NewMutex creates and returns a new mutex.
|
||||
func NewMutex() *Mutex {
|
||||
return &Mutex{
|
||||
wid : gtype.NewInt64(),
|
||||
rcount : gtype.NewInt(),
|
||||
wcount : gtype.NewInt(),
|
||||
wid : gtype.NewInt64(),
|
||||
state : gtype.NewInt32(),
|
||||
locking : gtype.NewBool(),
|
||||
}
|
||||
}
|
||||
|
||||
// Lock locks mutex for writing.
|
||||
// Lock locks the mutex for writing.
|
||||
// If the lock is already locked for reading or writing,
|
||||
// Lock blocks until the lock is available.
|
||||
func (m *Mutex) Lock() {
|
||||
m.wcount.Add(1)
|
||||
m.mu.Lock()
|
||||
m.wid.Add(1)
|
||||
if m.locking.Cas(false, true) {
|
||||
m.mu.Lock()
|
||||
// State should be changed after locks.
|
||||
m.state.Set(-1)
|
||||
m.wid.Add(1)
|
||||
m.locking.Set(false)
|
||||
} else {
|
||||
runtime.Gosched()
|
||||
m.Lock()
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock unlocks the write lock.
|
||||
// It is safe to be called multiple times.
|
||||
// Unlock unlocks the writing lock.
|
||||
// It is safe to be called multiple times if there's any locks or not.
|
||||
func (m *Mutex) Unlock() {
|
||||
if m.wcount.Val() > 0 {
|
||||
if m.wcount.Add(-1) >= 0 {
|
||||
m.mu.Unlock()
|
||||
} else {
|
||||
m.wcount.Add(1)
|
||||
}
|
||||
}
|
||||
if m.state.Cas(-1, 0) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// TryLock tries locking the mutex for writing.
|
||||
// It returns true if success, or if there's a write/reading lock on the mutex,
|
||||
// it returns false.
|
||||
func (m *Mutex) TryLock() bool {
|
||||
if m.locking.Cas(false, true) {
|
||||
if m.state.Cas(0, -1) {
|
||||
m.mu.Lock()
|
||||
m.wid.Add(1)
|
||||
m.locking.Set(false)
|
||||
return true
|
||||
}
|
||||
m.locking.Set(false)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RLock locks mutex for reading.
|
||||
// If the mutex is already locked for writing,
|
||||
// It blocks until the lock is available.
|
||||
func (m *Mutex) RLock() {
|
||||
m.rcount.Add(1)
|
||||
m.mu.RLock()
|
||||
if m.locking.Cas(false, true) {
|
||||
m.mu.RLock()
|
||||
// State should be changed after locks.
|
||||
m.state.Add(1)
|
||||
m.locking.Set(false)
|
||||
} else {
|
||||
runtime.Gosched()
|
||||
m.RLock()
|
||||
}
|
||||
}
|
||||
|
||||
// RUnlock undoes a single RLock call;
|
||||
// it does not affect other simultaneous readers.
|
||||
// It is a run-time error if mutex is not locked for reading
|
||||
// on entry to RUnlock.
|
||||
// It is safe to be called multiple times.
|
||||
// RUnlock unlocks the reading lock.
|
||||
// It is safe to be called multiple times if there's any locks or not.
|
||||
func (m *Mutex) RUnlock() {
|
||||
if m.rcount.Val() > 0 {
|
||||
if m.rcount.Add(-1) >= 0 {
|
||||
m.mu.RUnlock()
|
||||
} else {
|
||||
m.rcount.Add(1)
|
||||
}
|
||||
if n := m.state.Val(); n >= 1 {
|
||||
if m.state.Cas(n, n - 1) {
|
||||
m.mu.RUnlock()
|
||||
} else {
|
||||
m.RUnlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TryLock tries locking the mutex for writing.
|
||||
// It returns true if success, or if there's a write/read lock on the mutex,
|
||||
// it returns false.
|
||||
func (m *Mutex) TryLock() bool {
|
||||
// The first check, but it cannot ensure the atomicity.
|
||||
if m.wcount.Val() == 0 && m.rcount.Val() == 0 {
|
||||
// The second check, it ensures the atomicity with atomic Add.
|
||||
if m.wcount.Add(1) == 1 {
|
||||
m.mu.Lock()
|
||||
m.wid.Add(1)
|
||||
return true
|
||||
} else {
|
||||
m.wcount.Add(-1)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// TryRLock tries locking the mutex for reading.
|
||||
// It returns true if success, or if there's a write lock on the mutex, it returns false.
|
||||
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
|
||||
func (m *Mutex) TryRLock() bool {
|
||||
// There must be no write lock on mutex.
|
||||
if m.wcount.Val() == 0 {
|
||||
m.rcount.Add(1)
|
||||
m.mu.RLock()
|
||||
return true
|
||||
if m.locking.Cas(false, true) {
|
||||
if m.state.Val() >= 0 {
|
||||
m.mu.RLock()
|
||||
m.state.Add(1)
|
||||
m.locking.Set(false)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLocked checks whether the mutex is locked by writing or reading lock.
|
||||
func (m *Mutex) IsLocked() bool {
|
||||
return m.state.Val() != 0
|
||||
}
|
||||
|
||||
// IsRLocked checks whether the mutex is locked by writing lock.
|
||||
func (m *Mutex) IsWLocked() bool {
|
||||
return m.state.Val() < 0
|
||||
}
|
||||
|
||||
// IsRLocked checks whether the mutex is locked by reading lock.
|
||||
func (m *Mutex) IsRLocked() bool {
|
||||
return m.state.Val() > 0
|
||||
}
|
||||
|
||||
// TryLockFunc tries locking the mutex for writing with given callback function <f>.
|
||||
// it returns true if success, or if there's a write/read lock on the mutex,
|
||||
// it returns true if success, or if there's a write/reading lock on the mutex,
|
||||
// it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
@ -118,7 +145,7 @@ func (m *Mutex) TryLockFunc(f func()) bool {
|
||||
}
|
||||
|
||||
// TryRLockFunc tries locking the mutex for reading with given callback function <f>.
|
||||
// It returns true if success, or if there's a write lock on the mutex, it returns false.
|
||||
// It returns true if success, or if there's a writing lock on the mutex, it returns false.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) TryRLockFunc(f func()) bool {
|
||||
@ -131,7 +158,7 @@ func (m *Mutex) TryRLockFunc(f func()) bool {
|
||||
}
|
||||
|
||||
// LockFunc locks the mutex for writing with given callback function <f>.
|
||||
// If there's a write/read lock the mutex, it will blocks until the lock is released.
|
||||
// If there's a write/reading lock the mutex, it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) LockFunc(f func()) {
|
||||
@ -141,7 +168,7 @@ func (m *Mutex) LockFunc(f func()) {
|
||||
}
|
||||
|
||||
// RLockFunc locks the mutex for reading with given callback function <f>.
|
||||
// If there's a write lock the mutex, it will blocks until the lock is released.
|
||||
// If there's a writing lock the mutex, it will blocks until the lock is released.
|
||||
//
|
||||
// It releases the lock after <f> is executed.
|
||||
func (m *Mutex) RLockFunc(f func()) {
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -315,8 +316,12 @@ func getBacktrace(skip...int) string {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get the caller backtrace from business caller file.
|
||||
// Converting all file separator to "/".
|
||||
goRoot := runtime.GOROOT()
|
||||
if goRoot != "" {
|
||||
goRoot = strings.Replace(goRoot, "\\", "/", -1)
|
||||
goRoot = regexp.QuoteMeta(goRoot)
|
||||
}
|
||||
for i := from + customSkip; i < 10000; i++ {
|
||||
if _, file, cline, ok := runtime.Caller(i); ok && file != "" {
|
||||
if reg, _ := regexp.Compile(`<autogenerated>`); reg.MatchString(file) {
|
||||
|
@ -1,15 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"github.com/gogf/gf/g/container/garray"
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"github.com/gogf/gf/g/os/gmlock"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
wg.Add(-100)
|
||||
wg.Add()
|
||||
wg.Wait()
|
||||
fmt.Println(1)
|
||||
mu := gmlock.NewMutex()
|
||||
array := garray.New()
|
||||
go func() {
|
||||
mu.LockFunc(func() {
|
||||
array.Append(1)
|
||||
time.Sleep(10000 * time.Millisecond)
|
||||
})
|
||||
}()
|
||||
time.Sleep(10*time.Millisecond)
|
||||
for i := 0; i < 10000; i++ {
|
||||
go func(i int) {
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
mu.LockFunc(func() {
|
||||
glog.Print(i)
|
||||
array.Append(1)
|
||||
})
|
||||
}(i)
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(60 * time.Millisecond)
|
||||
mu.Unlock()
|
||||
mu.Unlock()
|
||||
mu.Unlock()
|
||||
}()
|
||||
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
gtest.Assert(array.Len(), 1)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
gtest.Assert(array.Len(), 1)
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
gtest.Assert(array.Len(), 3)
|
||||
}
|
||||
|
@ -1,20 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gmlock"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHookHandler("/*any", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.SetAllowCrossDomainRequest("*", "PUT,GET,POST,DELETE,OPTIONS")
|
||||
r.Response.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
r.Response.Header().Set("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, token")
|
||||
})
|
||||
s.Group("/v1").COMMON("*", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"name": "john"})
|
||||
})
|
||||
s.SetPort(6789)
|
||||
s.Run()
|
||||
key := "test3"
|
||||
gmlock.Lock(key, 200*time.Millisecond)
|
||||
fmt.Println("TryLock:", gmlock.TryLock(key))
|
||||
fmt.Println("TryLock:", gmlock.TryLock(key))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user