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