假设我有一个函数generateId
来生成随机的64位整数。如果我这样写generateId
uint64_t generateId() {
static thread_local std::mt19937_64 rng{std::random_device{}()};
return rng();
}
然后rng
将不会在分叉后重新播种。正在运行
int main() {
std::cout << generateId() << "\n";
if (fork() == 0) {
std::cout << "child: " << generateId() << "\n";
} else {
std::cout << "parent: " << generateId() << "\n";
}
return 0;
}
将为孩子和父母打印相同的数字。
有没有一种我可以写generateId
的方式,以便它可以用于新进程,但仍保持高性能。
答案 0 :(得分:1)
这是我想出的:
class TlsRandomNumberGenerator {
public:
TlsRandomNumberGenerator() {
pthread_atfork(nullptr, nullptr, OnFork);
}
static uint64_t GenerateId() {
return random_number_generator_();
}
private:
static thread_local std::mt19937_64 random_number_generator_;
static void OnFork() {
random_number_generator_.seed(std::random_device{}());
}
};
thread_local std::mt19937_64 TlsRandomNumberGenerator::random_number_generator_{
std::random_device{}()};
uint64_t generateId() {
static TlsRandomNumberGenerator rng;
return TlsRandomNumberGenerator::GenerateId();
}
它可以与派生一起使用,但也没有每个数字生成都调用getpid
的开销,这取决于您所使用的libc版本可能会或可能不会被缓存,因此可能会影响性能罚款。请参见getpid
上的注释:
从glibc 2.3.4版到2.24版(包括2.24版),glibc getpid()缓存的PID的包装函数,目的是避免 进程重复调用getpid()时,会进行其他系统调用。
答案 1 :(得分:0)
这应该有效:
Option Explicit
Sub FillColumnAccordingToFilteredRows()
Dim bidNum As String
Dim bidFull As String
Dim PriceLObj As ListObject
bidNum = "123" 'sample number
bidFull = "Bid-" + bidNum + ".csv"
Set PriceLObj = ActiveSheet.ListObjects("PriceExp") ' set the ListObject
PriceLObj.Range.AutoFilter Field:=1, Criteria1:=bidFull ' filters data by Bid #
Dim VisRng As Range, VisArea As Range, VisRow As Range
Dim ColBRng As Range, ColCRng As Range
' get the visible range of the filteres list object
Set VisRng = PriceLObj.Range.SpecialCells(xlCellTypeVisible)
' === set column B and column C Range ===
For Each VisArea In VisRng.Areas ' loop through areas in non-contigous filtered range
' loop through rows in area
For Each VisRow In VisRng.Rows
If VisRow.Row <> 1 Then ' not header row
' set and Merge ranges for column B range
If Not ColBRng Is Nothing Then
Set ColBRng = Application.Union(ColBRng, Range("B" & VisRow.Row))
Else
Set ColBRng = Range("B" & VisRow.Row)
End If
' set and Merge ranges for column C range
If Not ColCRng Is Nothing Then
Set ColCRng = Application.Union(ColCRng, Range("C" & VisRow.Row))
Else
Set ColCRng = Range("C" & VisRow.Row)
End If
End If
Next VisRow
Next VisArea
' make sure column B range is not empty (otherwise will pop an error)
If Not ColBRng Is Nothing Then ColBRng.Value2 = "sample name"
' make sure column C range is not empty (otherwise will pop an error)
If Not ColCRng Is Nothing Then ColCRng.Value2 = "sample state"
End Sub
注意:此代码不是线程安全的,并且假设您尝试使用uint64_t generateId() {
static pid_t mypid = 0;
static std::unqiue_ptr<std::mt19937_64> rng;
if( mypid != getpid() ) {
rng.reset();
mypid = getpid();
}
if( !rng )
rng = std::make_unique<std::mt19937_64>(std::random_device{}());
return (*rng)();
}
解决thread_local
问题,因此我删除了fork()
。如果涉及多线程,则必须进行适当的锁定以及使用mutexes
或使用fork()
的非阻塞原语的问题的考虑因素