syncOnce的Go语言与C++11实现方法

          Go语言中的sync.Once,用于实现"只执行一次"的功能。功能与pthread_once()差不多。
但pthread_once()可不通用,不过现在C++11终于有了std::call_once来实现这一功能。

虽然一个面向协程,一个面向线程,但这个点要实现的功能是一样的,把两种语言的实现记录一下。  

       在   http://www.cplusplus.com/reference/mutex/call_once/ 有C++11的相关例子,但用了很多新特性。

简化下,便于做对比.

   没有传任何参数的 C++/Go例 子: 

// call_once example
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <mutex>          // std::call_once, std::once_flag

std::once_flag flag;
int Gid = 0;

void setup()
{
	Gid++;
	std::cout << "Called once " << Gid << std::endl;
}


void doprint()
{	
	std::call_once(flag, setup);
}

int main()
{
	std::thread t1(doprint);
	std::thread t2(doprint);
	std::thread t3(doprint);
	std::thread t4(doprint);

	t1.join();
	t2.join();
	t3.join();
	t4.join();

	std::cout << "Gid: " << Gid << std::endl;
}
   

  Go例子:

package main

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

var once sync.Once
var Gid int

func setup() {
	Gid++
	fmt.Println("Called once")
}

func doprint() {
	once.Do(setup)
	fmt.Println("doprint()...")
}

func main() {

	go doprint()
	go doprint()
	go doprint()
	go doprint()

	time.Sleep(time.Second)
	fmt.Println("Gid:", Gid)
}

    关于参数传递,C++是很容易解决的,直接在call_once后面加就行了 。

// call_once example
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <mutex>          // std::call_once, std::once_flag

std::once_flag flag;
int Gid = 0;

void setup(std::string parm)
{
	Gid++;
	std::cout << "Called once! " << Gid << " parm:" << parm.c_str() << std::endl;
}

void doprint(std::string parm)
{	
	std::call_once(flag, setup, parm);
}

int main()
{
	std::thread t1(doprint, "1");
	std::thread t2(doprint, "2");
	std::thread t3(doprint, "3");
	std::thread t4(doprint, "4");

	t1.join();
	t2.join();
	t3.join();
	t4.join();

	std::cout << "Gid: " << Gid << std::endl;
}
        Go语言的sync.Once后面不允许直接传参数,但可以通过以下方法来变通。

package main

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

var once sync.Once
var Gid int

func doprint(parm string) {
	setup := func() {
		Gid++
		fmt.Println("Called once! parm:", parm)
	}
	once.Do(setup)
	fmt.Println("doprint()...")
}

func main() {

	go doprint("1")
	go doprint("2")
	go doprint("3")
	go doprint("4")

	time.Sleep(time.Second)
	fmt.Println("Gid:", Gid)
}

   完毕!



MAIL: xcl_168@aliyun.com

BLOG:http://blog.csdn.net/xcl168




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Go 语言中,可以使用 `const` 和 `var` 来定义常量和变量,但是它们不能像 C++ 中的 `#define` 一样实现简单的文本替换。不过,我们可以通过自定义代码生成工具来实现类似 `#define` 的功能。 首先,我们可以在代码中定义一个占位符(例如 `{{NAME}}`),然后使用代码生成工具将占位符替换为相应的值。 以下是一个示例实现: 定义一个 `defines.go` 文件,用于存储我们的定义: ```go package defines const ( MaxConnections = 100 BufferSize = 1024 PortNumber = 8080 ) ``` 然后,我们可以编写一个代码生成工具 `definegen.go`,该工具读取 `defines.go` 中的定义,并生成一个新的文件 `defines.gen.go`,其中包含了替换后的代码: ```go //go:generate go run definegen.go package defines import ( "io/ioutil" "strings" ) const definesTemplate = ` package defines const ( MaxConnections = {{MAX_CONNECTIONS}} BufferSize = {{BUFFER_SIZE}} PortNumber = {{PORT_NUMBER}} )` func main() { template := strings.ReplaceAll(definesTemplate, "{{MAX_CONNECTIONS}}", "100") template = strings.ReplaceAll(template, "{{BUFFER_SIZE}}", "1024") template = strings.ReplaceAll(template, "{{PORT_NUMBER}}", "8080") err := ioutil.WriteFile("defines.gen.go", []byte(template), 0644) if err != nil { panic(err) } } ``` 最后,我们可以使用以下命令来运行代码生成工具: ``` go generate ``` 执行此命令后,会自动生成一个名为 `defines.gen.go` 的文件,其中包含了替换后的代码。我们可以在其他文件中导入 `defines` 包,并直接使用其中定义的常量。例如: ```go package main import ( "fmt" "path/to/defines" ) func main() { fmt.Printf("Max connections: %d\n", defines.MaxConnections) fmt.Printf("Buffer size: %d\n", defines.BufferSize) fmt.Printf("Port number: %d\n", defines.PortNumber) } ``` 注意,此方法仅适用于非常简单的文本替换。如果需要更复杂的宏定义,建议使用其他编程语言实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值