ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

goroutine和chan

2022-03-09 04:31:06  阅读:171  来源: 互联网

标签:return err syscall goroutine chan int var GetCurrentThreadId


package main

import (
	"errors"
	"fmt"
	"reflect"
	"sync"
	"syscall"
	"unsafe"
)

var wg sync.WaitGroup
var once sync.Once

type Str struct {
	num int
	pid int
}
type hchan struct {
	qcount   uint           // total data in the queue
	dataqsiz uint           // size of the circular queue
	buf      unsafe.Pointer // points to an array of dataqsiz elements
	elemsize uint16
	closed   uint32
}

type ChanInfo struct {
	Closed bool // 是否关闭
	Len    uint // channel内数据量
	Cap    uint // channel容量
	Block  bool // 是否已经阻塞
}

func ChanStatus(c interface{}) (*ChanInfo, error) {
	v := reflect.ValueOf(c)
	if v.Type().Kind() != reflect.Chan {
		return nil, errors.New("type must be channel")
	}
	i := (*[2]uintptr)(unsafe.Pointer(&c))
	h := (*hchan)(unsafe.Pointer(i[1]))
	return &ChanInfo{
		Cap:    h.dataqsiz,
		Len:    h.qcount,
		Closed: h.closed == 1,
		Block:  h.qcount >= h.dataqsiz,
	}, nil
}
func GetCurrentThreadId() int {
	var user32 *syscall.DLL
	var GetCurrentThreadId *syscall.Proc
	var err error

	user32, err = syscall.LoadDLL("Kernel32.dll")
	if err != nil {
		fmt.Printf("syscall.LoadDLL fail: %v\n", err.Error())
		return 0
	}
	GetCurrentThreadId, err = user32.FindProc("GetCurrentThreadId")
	if err != nil {
		fmt.Printf("user32.FindProc fail: %v\n", err.Error())
		return 0
	}

	var pid uintptr
	pid, _, err = GetCurrentThreadId.Call()

	return int(pid)
}

func f1(ch1 chan int) {
	defer wg.Done()
	for i := 0; i < 98; i++ {
		ch1 <- i
	}
	ch1 <- 666
	ch1 <- 666
	close(ch1)
}

func f2(ch1 chan int, ch2 chan Str) {

	defer wg.Done()
	for {
		//ChanInfo, _ := ChanStatus(ch1)
		x, ok := <-ch1
		if x == 666 && ok == true {
			break
		}
		var s Str
		s.num = x
		s.pid = GetCurrentThreadId()
		//if ChanInfo.Closed {
		ch2 <- s
		//}
	}
}

func f3(ch1 chan int, ch2 chan Str) {

	defer wg.Done()
	for {
		x, ok := <-ch1
		if !ok {
			break
		}
		var s Str
		s.num = x
		s.pid = GetCurrentThreadId()
		ch2 <- s //可能是运行到这

	}
	// close(ch2)
	once.Do(func() { close(ch2) })
}

func main() {

	ch1 := make(chan int, 100)
	ch2 := make(chan Str, 100)
	// ch3 := make(chan Str, 100)
	wg.Add(3)

	go f1(ch1)
	go f2(ch1, ch2)
	go f2(ch1, ch2)
	wg.Wait()
	close(ch2)
	for {
		x, ok := <-ch2
		if !ok {
			break
		}
		fmt.Println(x.num, x.pid)
	}
	// 直接判断状态会有问题,就是运行的时候可能是这个函数先运行了,第一次就直接ok==false跳出了
	//于是我拿到了chan的结构信息,想通过长度或者close的状态是否关闭来判断,就又会有可能出现在同一个索引上取值,或者第一个运行到关闭那了,第二个运行到赋值那了
	//因为两个结束标记是666 ,第一个线程判断第一个666为真就跳出去执行了,但是第二个线程要么拿到第二个666然后跳出,要么跟第一个同时拿到,因为值被第一个拿了,
	//第二个就拿了个空,还继续去赋值,还在赋值的时候,第一个又还没执行到close的可能,就panic: send on closed channel
	//close要在外部关闭, 关闭后不能继续赋值

}

  

标签:return,err,syscall,goroutine,chan,int,var,GetCurrentThreadId
来源: https://www.cnblogs.com/dzs894330350/p/15983373.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有