{"id":2304,"date":"2015-04-21T00:21:49","date_gmt":"2015-04-20T23:21:49","guid":{"rendered":"http:\/\/roboblog.fatal-fury.de\/?p=2304"},"modified":"2015-04-21T12:05:27","modified_gmt":"2015-04-21T11:05:27","slug":"calling-multiple-random-generator-in-parallel-c11","status":"publish","type":"post","link":"http:\/\/roboblog.fatal-fury.de\/?p=2304","title":{"rendered":"Calling multiple random generator in parallel c++11"},"content":{"rendered":"<p>Standard random functions are not thread safe. Calling them in parallel may result in undefined behavior or the threads blocking each other. This is a little test to create the same random sequences in serial as in parallel too.<\/p>\n<p>Setting the same seed on a random generator as a start point should produce the same random sequence. First we create one generator and print the first three numbers. Restart it with different seed numbers.<br \/>\nThen we create three random generators with the same seeds and call them parallel. They should create the same sequences even if they are called interleaved.<\/p>\n<p>Program output:<\/p>\n<blockquote><p>seriell<br \/>\nseed 1<br \/>\n48271<br \/>\n182605794<br \/>\n1291394886<\/p>\n<p>seed 2<br \/>\n96542<br \/>\n365211588<br \/>\n435306125<\/p>\n<p>seed 3<br \/>\n144813<br \/>\n547817382<br \/>\n1726701011<\/p>\n<p>parallel<br \/>\nThread 0 seed 1: 48271<br \/>\nThread 0 seed 1: 182605794<br \/>\nThread 0 seed 1: 1291394886<br \/>\nThread 1 seed 2: 96542<br \/>\nThread 1 seed 2: 365211588<br \/>\nThread 1 seed 2: 435306125<br \/>\nThread 2 seed 3: 144813<br \/>\nThread 2 seed 3: 547817382<br \/>\nThread 2 seed 3: 1726701011\n<\/p><\/blockquote>\n<p>Yep, work as expected :D<br \/>\nThe program looks not as simple as it might can be. But I think it is okay.<\/p>\n<pre><code>void waitlong() {\r\n  long a = 0;\r\n  for(int i=0; i < 1000000; i++) {\r\n      a += i;\r\n  }\r\n}\r\n\r\nint main() {\r\n  \/\/ create some random number and store them in expectedResult\r\n  int expectedResult[3][3] = { 0 };\r\n  std::minstd_rand generator;\r\n\r\n  std::cout << \"seriell\\n\";\r\n\r\n  for(int id=0; id < 3; id++) {\r\n    generator.seed(id+1);\r\n    std::cout << \"seed \" << id+1 << \"\\n\";\r\n    for(int i=0; i < 3; i++) {\r\n      expectedResult[id][i] = generator();\r\n      std::cout << expectedResult[id][i] << \"\\n\";\r\n    }\r\n  }\r\n\r\n  \/\/ create three generators with the same seed and call them parallel\r\n  std::cout << \"\\nparallel\\n\";\r\n\r\n  std::minstd_rand generators[3];\r\n  generators[0].seed(1);\r\n  generators[1].seed(2);\r\n  generators[2].seed(3);\r\n\r\n  int result[3][3] = { 0 };\r\n  int count = 0;\r\n\r\n  \/\/ create 3 threads and interleave them with schedule(static, 1) num_threads(3)\r\n  \/\/ We can not call cout in a threaded enviroment. So we must store the random numbers\r\n  \/\/ in a array and print them laster. count and result is for this.\r\n#pragma omp parallel for firstprivate(count) shared(result) schedule(static, 1) num_threads(3)\r\n  for(int i=0; i < 3*3; i++) {\r\n    int id = omp_get_thread_num();\r\n    int rand = generators[id]();\r\n\r\n    \/\/ not error free even with omp critical\r\n\/\/     std::cout << \"Thread \" << id << \" seed \" << id+1 << \": \" << rand << \"\\n\";\r\n\r\n    result[id][count++] = rand;\r\n\r\n    \/\/ wait a litte bit to give the next thread a chance to start\r\n    waitlong();\r\n  }\r\n\r\n  \/\/ now print and compre the results\r\n  for(int id=0; id < 3; id++) {\r\n    for(int i=0; i < 3; i++) {\r\n      std::cout << \"Thread \" << id << \" seed \" << id+1 << \": \" << result[id][i] << \"\\n\";\r\n      if(result[id][i] != expectedResult[id][i]) {\r\n        std::cout << \"but expected \" << expectedResult[id][i] << \"\\n\";\r\n      }\r\n    }\r\n  }\r\n\r\n  std::cout << \"\\nValues per seed must be equal\\n\";\r\n  return 0;\r\n}\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Standard random functions are not thread safe. Calling them in parallel may result in undefined behavior or the threads blocking each other. This is a little test to create the same random sequences in serial as in parallel too. Setting the same seed on a random generator as a start point should produce the same [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[17],"class_list":["post-2304","post","type-post","status-publish","format-standard","hentry","category-allgemein","tag-cpp"],"_links":{"self":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2304","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2304"}],"version-history":[{"count":7,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2304\/revisions"}],"predecessor-version":[{"id":2314,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=\/wp\/v2\/posts\/2304\/revisions\/2314"}],"wp:attachment":[{"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2304"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/roboblog.fatal-fury.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}