Golang实现简易读写锁(带注释,可运行)

1、简单读写锁实现,未实现写优先逻辑。

(1)代码:

package main

import (
	"fmt"
	"sync"
	"time"
)

type RWLock struct {
    readCount  int
    writeCount int
    mutex      sync.Mutex // 一个互斥锁,用于保护共享变量的读写操作。
    readCond   sync.Cond // 一个条件变量,用于协调读操作和写操作。
    writeCond  sync.Cond
}

// 给条件变量 (readCond 和 writeCond) 设置它们的关联互斥锁
func (rw *RWLock) Init() {
    rw.readCond.L = &rw.mutex
	// 调用 readCond.Wait() 时,它会自动释放 rw.mutex,并在条件满足时重新获取它。
    rw.writeCond.L = &rw.mutex
}

// RLock方法中,首先获取锁,然后判断是否有写操作正在进行,如果有,则调用条件变量的Wait方法等待,直到写计数器为0。然后将读计数器加1,并释放锁。
func (rw *RWLock) RLock() {
    rw.mutex.Lock()
    for rw.writeCount > 0 {
        rw.readCond.Wait() // 将当前 goroutine 置于等待状态,并在收到通知后重新尝试获取锁。自动释放 rw.mutex,并在条件满足时重新获取它。
    }
    rw.readCount++
    rw.mutex.Unlock()
}



// RUnlock方法中,获取锁,将读计数器减1,如果读计数器为0,则唤醒写操作的等待者,并释放锁。
func (rw *RWLock) RUnlock() {
    rw.mutex.Lock()
    rw.readCount--
    if rw.readCount == 0 {
        rw.writeCond.Signal() // 调用了Signal()或Broadcast()方法来唤醒。
    }
    rw.mutex.Unlock()
}

// WLock方法中,首先获取锁,然后判断是否有其他读操作或写操作正在进行,如果有,则调用条件变量的Wait方法等待,
// 直到读计数器和写计数器都为0。然后将写计数器加1,并释放锁。
func (rw *RWLock) WLock() {
    rw.mutex.Lock()
    for rw.readCount > 0 || rw.writeCount > 0 {
        rw.writeCond.Wait()
    }
    rw.writeCount++
    rw.mutex.Unlock()
}


// 获取锁,将写计数器减1,然后分别唤醒读操作和写操作的等待者,并释放锁。
func (rw *RWLock) WUnlock() {
    rw.mutex.Lock()
    rw.writeCount--
	rw.readCond.Signal()
	rw.writeCond.Signal()
    rw.mutex.Unlock()
}


func main() {
	var rwLock RWLock
	rwLock.Init() 

	var wg sync.WaitGroup
	numReaders := 4
	numWriters := 3

	// 创建写者 goroutine
	for i := 0; i < numWriters; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			fmt.Printf("Writer %d is trying to write\n", id)
			rwLock.WLock()
			fmt.Printf("Writer %d is writing\n", id)
			time.Sleep(2 * time.Second) // 模拟写入操作的时间
			rwLock.WUnlock()
			fmt.Printf("Writer %d finished writing\n", id)
		}(i)
	}

	// 创建读者 goroutine
	for i := 0; i < numReaders; i++ {
		wg.Add(1)
		go func(id int) {
			defer wg.Done()
			fmt.Printf("Reader %d is trying to read\n", id)
			rwLock.RLock()
			fmt.Printf("Reader %d is reading\n", id)
			time.Sleep(time.Second) // 模拟读取操作的时间
			rwLock.RUnlock()
			fmt.Printf("Reader %d finished reading\n", id)
		}(i)
	}

	wg.Wait()
	fmt.Println("All readers and writers have finished")
}

(2)运行结果:

(3)To do:实现写优先逻辑

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个基本的TUN设备读写的示例代码: ```go package main import ( "fmt" "log" "net" "os" "syscall" ) const ( TUN_NAME = "tun0" TUN_IP = "10.0.0.1" TUN_MASK = "255.255.255.0" TUN_ROUTE = "10.0.0.0/24" ) func main() { // 创建TUN设备 fd, err := syscall.Open("/dev/net/tun", os.O_RDWR, 0) if err != nil { log.Fatal(err) } ifreq := &syscall.IFreq{Name: [16]byte{TUN_NAME[0], TUN_NAME[1], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} ifreq.Flags = syscall.IFF_TUN | syscall.IFF_NO_PI if err := syscall.IoctlSetInt(fd, syscall.TUNSETIFF, uintptr(unsafe.Pointer(ifreq))); err != nil { log.Fatal(err) } // 设置IP地址和路由 link, err := net.InterfaceByName(TUN_NAME) if err != nil { log.Fatal(err) } addr, err := netlink.ParseAddr(fmt.Sprintf("%s/%s", TUN_IP, TUN_MASK)) if err != nil { log.Fatal(err) } if err := netlink.AddrAdd(link, addr); err != nil { log.Fatal(err) } route := &netlink.Route{ LinkIndex: link.Index, Dst: &net.IPNet{ IP: net.ParseIP(TUN_ROUTE), Mask: net.CIDRMask(24, 32), }, } if err := netlink.RouteAdd(route); err != nil { log.Fatal(err) } // 读取数据 buf := make([]byte, 1500) for { n, err := syscall.Read(fd, buf) if err != nil { log.Fatal(err) } fmt.Printf("Received %d bytes from tunnel: %v\n", n, buf[:n]) // 处理数据 // ... // 发送数据 n, err = syscall.Write(fd, buf[:n]) if err != nil { log.Fatal(err) } fmt.Printf("Sent %d bytes to tunnel: %v\n", n, buf[:n]) } } ``` 需要注意以下几点: 1. 创建TUN设备需要打开`/dev/net/tun`设备文件,并使用`TUNSETIFF`命令设置设备类型和名称。 2. 设置IP地址和路由可以使用`netlink`包。 3. 读写数据可以使用`syscall.Read`和`syscall.Write`系统调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rebecca.Yan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值