diff --git a/R/RcppExports.R b/R/RcppExports.R index 418d3dda..58a0263d 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -13,6 +13,18 @@ readEnvironmentFromSharedMemory <- function(shared_memory_name) { .Call(`_processR_readEnvironmentFromSharedMemory`, shared_memory_name) } +CreateSharedEnvironment <- function(name) { + .Call(`_processR_CreateSharedEnvironment`, name) +} + +CreateSharedEnvironmentNoReturn <- function(name) { + invisible(.Call(`_processR_CreateSharedEnvironmentNoReturn`, name)) +} + +readSharedEnvironment <- function(name) { + .Call(`_processR_readSharedEnvironment`, name) +} + RunProcess <- function(fun, env) { invisible(.Call(`_processR_RunProcess`, fun, env)) } diff --git a/inst/include/ProcessR.hpp b/inst/include/ProcessR.hpp index 0388397e..523da278 100644 --- a/inst/include/ProcessR.hpp +++ b/inst/include/ProcessR.hpp @@ -1,73 +1,429 @@ #ifndef PROCESSR_HPP #define PROCESSR_HPP -// -// #include -// #include -// -// -// class Child{ -// boost::process::child child_m; -// -// public: -// int rank; -// Rcpp::RawVector fun;//serialized function -// Rcpp::RawVector env;//serialized environment -// -// -// Child(Rcpp::Function fun, Rcpp::Environment env){ -// } -// -// -// -// void start(Rcpp::Function fun, Rcpp::Environment env){ -// -// } -// -// void join(){ -// -// } -// -// void Kill(){ -// -// } -// -// }; -// -// // [[Rcpp::export]] -// void Run(Rcpp::Function fun, Rcpp::Environment env){ -// std::string path ="/Users/mattadmin/rprojects/processR/src/RRunner.x"; -// Rcpp::RawVector serialized_fun; -// { -// Rcpp::Function serializeFunc("serialize"); -// serialized_fun = serializeFunc(fun); -// } -// -// Rcpp::RawVector serialized_env; -// { -// Rcpp::Function serializeEnv("serialize"); -// serialized_env = serializeEnv(env); -// } -// boost::process::ipstream child_output; -// boost::process::opstream child_input; -// -// boost::process::child childProcess(path, -// boost::process::std_in < child_input, // Redirect parent's input to child's output -// boost::process::std_out > child_output // Redirect child's output to parent's input -// ); -// -// child_input << serialized_fun.size(); -// child_input<< serialized_fun; -// -// childProcess.join(); -// } -// -// /** -// * Returns a list of children. -// */ -// Rcpp::List CreateFamily(int size){ -// -// } -// + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::interprocess; + +typedef allocator SharedIntAllocator; +typedef allocator SharedRealAllocator; +typedef allocator SharedCharAllocator; +typedef std::vector SharedIntVector; +typedef std::vector SharedRealVector; + + + +//This allocator will allow placing containers in the segment +typedef allocator ShmemAllocator; + +//Alias a vector that uses the previous STL-like allocator so that allocates +//its values from the segment +typedef vector REALSMVector; + + +/** + * Wrapper class for std::vector types. If this file is compiled with -DTMB_MODEL, + * conversion operators are defined for TMB vector types. + */ +class SharedVector { + managed_shared_memory segment; + REALSMVector* vec_m; + + /** + * @brief friiend comparison operator. + */ + friend bool operator==(const SharedVector& lhs, + const SharedVector& rhs); + + void init(const std::string name) { + + shared_memory_object::remove(name.c_str()); + + //Create a new segment with given name and size + segment = managed_shared_memory(create_only, name.c_str(), 65536); + + //Initialize shared memory STL-compatible allocator + const ShmemAllocator alloc_inst(segment.get_segment_manager()); + + //Construct a vector named "MyVector" in shared memory with argument alloc_inst + this->vec_m = segment.construct("REALSMVector")(alloc_inst); + + } + +public: + //Member Types + + typedef typename REALSMVector::value_type value_type; /*!*/ + typedef typename REALSMVector::allocator_type allocator_type; /*!*/ + typedef typename REALSMVector::size_type size_type; /*!*/ + typedef typename REALSMVector::difference_type difference_type; /*!*/ + typedef typename REALSMVector::reference reference; /*!*/ + typedef typename REALSMVector::const_reference const_reference; /*!*/ + typedef typename REALSMVector::pointer pointer; /*!*/ + typedef typename REALSMVector::const_pointer const_pointer; /*!*/ + typedef typename REALSMVector::iterator iterator; /*!*/ + typedef typename REALSMVector::const_iterator const_iterator; /*!*/ + typedef typename REALSMVector::reverse_iterator reverse_iterator; /*!*/ + typedef typename REALSMVector::const_reverse_iterator const_reverse_iterator; /*!*/ + + /** + * Default constructor. + */ + SharedVector() { + std::stringstream ss; + + std::time_t t = std::time(0); + ss<<"REALSMVector_"<init(ss.str().c_str()); + } + + /** + * @brief Constructs the container of size copies of elements with value value. + */ + SharedVector(size_t size, const double& value = double()) { + this->vec_m->resize(size, value); + } + + /** + * @brief Copy constructor. + */ + SharedVector(const SharedVector& other) { + this->vec_m->resize(other.size()); + for (size_t i = 0; i < this->vec_m->size(); i++) { + this->vec_m->at(i) = other[i]; + } + } + + /** + * @brief Initialization constructor with std::vector type.. + */ + SharedVector(const std::vector& other) { + this->vec_m->resize(other.size()); + for (size_t i = 0; i < this->vec_m->size(); i++) { + this->vec_m->at(i) = other[i]; + } + } + + void create(const std::string& name) { + this->init(name); + } + + void open(const std::string& name) { + //Open the managed segment + this->segment = managed_shared_memory(open_only, name.c_str()); + + //Find the vector using the c-string name + this->vec_m = segment.find("REALSMVector").first; + } + + void destroy(const std::string& name) { + this->segment.destroy(name.c_str()); + } + + /** + * @brief Returns a reference to the element at specified location pos. No bounds checking is performed. + */ + inline double& operator[](size_t pos) { + return (*this->vec_m)[pos]; + } + + /** + * @brief Returns a constant reference to the element at specified location pos. No bounds checking is performed. + */ + inline const double& operator[](size_t n) const { + return (*this->vec_m)[n]; + } + + /** + * @brief Set an element at specified location pos. + */ + inline void set(size_t pos, double value) { + this->vec_m->at(pos) = value; + } + + /** + * @brief Set an element at specified location pos. + */ + inline double get(size_t pos) { + return this->vec_m->at(pos); + } + + /** + * @brief Returns a reference to the element at specified location pos. Bounds checking is performed. + */ + inline double& at(size_t n) { + return this->vec_m->at(n); + } + + /** + * @brief Returns a constant reference to the element at specified location pos. Bounds checking is performed. + */ + inline const double& at(size_t n) const { + return this->vec_m->at(n); + } + + /** + * @brief Returns a reference to the first element in the container. + */ + reference front() { + return this->vec_m->front(); + } + + /** + * @brief Returns a constant reference to the first element in the container. + */ + const_reference front() const { + return this->vec_m->front(); + } + + /** + * @brief Returns a reference to the last element in the container. + */ + reference back() { + return this->vec_m->back(); + } + + /** + * @brief Returns a constant reference to the last element in the container. + */ + const_reference back() const { + return this->vec_m->back(); + } + + /** + * @brief Returns a pointer to the underlying data array. + */ + pointer data() { + return this->vec_m->data(); + } + + /** + * @brief Returns a constant pointer to the underlying data array. + */ + const_pointer data() const { + return this->vec_m->data(); + } + + //iterators + + /** + * @brief Returns an iterator to the first element of the vector. + */ + iterator begin() { + return this->vec_m->begin(); + } + + /** + * @brief Returns an iterator to the element following the last element of the vector. + */ + iterator end() { + return this->vec_m->end(); + } + + /** + * @brief Returns an constant iterator to the first element of the vector. + */ + const_iterator begin() const { + return this->vec_m->begin(); + } + + /** + * @brief Returns an const iterator to the element following the last element of the vector. + */ + const_iterator end() const { + return this->vec_m->end(); + } + + /** + * @brief Returns a reverse iterator to the first element of the reversed vector. It corresponds to the last element of the non-reversed vector. + */ + reverse_iterator rbegin() { + return this->vec_m->rbegin(); + } + + /** + * @brief Returns a reverse iterator to the element following the last element of the reversed vector. It corresponds to the element preceding the first element of the non-reversed vector. + */ + reverse_iterator rend() { + return this->vec_m->rend(); + } + + /** + * @brief Returns a constant reverse iterator to the first element of the reversed vector. It corresponds to the last element of the non-reversed vector. + */ + const_reverse_iterator rbegin() const { + return this->vec_m->rbegin(); + } + + /** + * @brief Returns a constant reverse iterator to the element following the last element of the reversed vector. It corresponds to the element preceding the first element of the non-reversed vector. + */ + const_reverse_iterator rend() const { + return this->vec_m->rend(); + } + + //capacity + + /** + * @brief Checks whether the container is empty. + */ + bool empty() { + return this->vec_m->empty(); + } + + /** + * @brief Returns the number of elements. + */ + size_type size() const { + return this->vec_m->size(); + } + + /** + * @brief Returns the maximum possible number of elements. + */ + size_type max_size() const { + return this->vec_m->max_size(); + } + + /** + * @brief Reserves storage. + */ + void reserve(size_type cap) { + this->vec_m->reserve(cap); + } + + /** + * @brief Returns the number of elements that can be held in currently allocated storage. + */ + size_type capacity() { + return this->vec_m->capacity(); + } + + /** + * @brief Reduces memory usage by freeing unused memory. + */ + void shrink_to_fit() { + this->vec_m->shrink_to_fit(); + } + + //modifiers + + /** + * @brief Clears the contents. + */ + void clear() { + this->vec_m->clear(); + } + + /** + * @brief Inserts value before pos. + */ + iterator insert(const_iterator pos, const double& value) { + return this->vec_m->insert(pos, value); + } + + /** + * @brief Inserts count copies of the value before pos. + */ + iterator insert(const_iterator pos, size_type count, const double& value) { + return this->vec_m->insert(pos, count, value); + } + + /** + * @brief Inserts elements from range [first, last) before pos. + */ + template< class InputIt > + iterator insert(const_iterator pos, InputIt first, InputIt last) { + return this->vec_m->insert(pos, first, last); + } + + /** + * @brief Inserts elements from initializer list ilist before pos. + */ + + iterator insert(const_iterator pos, std::initializer_list ilist) { + return this->vec_m->insert(pos, ilist); + } + + /** + * @brief Constructs element in-place. + */ + template< class... Args > + iterator emplace(const_iterator pos, Args&&... args) { + return this->vec_m->emplace(pos, std::forward(args)...); + } + + /** + * @brief Removes the element at pos. + */ + iterator erase(iterator pos) { + return this->vec_m->erase(pos); + } + + /** + * @brief Removes the elements in the range [first, last). + */ + iterator erase(iterator first, iterator last) { + return this->vec_m->erase(first, last); + } + + /** + * @brief Adds an element to the end. + */ + void push_back(const double&& value) { + this->vec_m->push_back(value); + } + + /** + * @brief Constructs an element in-place at the end. + */ + template< class... Args > + void emplace_back(Args&&... args) { + this->vec_m->emplace_back(std::forward(args)...); + } + + /** + * @brief Removes the last element. + */ + void pop_back() { + this->vec_m->pop_back(); + } + + /** + * @brief Changes the number of elements stored. + */ + void resize(size_t s) { + this->vec_m->resize(s); + } + + /** + * @brief Swaps the contents. + */ + void swap(SharedVector& other) { + this->vec_m->swap((*other.vec_m)); + } + + + +private: + +}; // end fims::Vector class + +/** + * @brief Comparison operator. + */ +bool operator==(const SharedVector& lhs, + const SharedVector& rhs) { + return (*lhs.vec_m) == (*rhs.vec_m); +} + #endif \ No newline at end of file diff --git a/src/ProcessR.cpp b/src/ProcessR.cpp index 038f6220..96613c8f 100644 --- a/src/ProcessR.cpp +++ b/src/ProcessR.cpp @@ -1,7 +1,13 @@ #include #include #include + +#include "../inst/include/ProcessR.hpp" + #include +#include + + #include #include #include @@ -523,7 +529,7 @@ class Process { // Process p; // return p; // } - +// // template // class SharedStorage{ // @@ -532,16 +538,42 @@ class Process { // SharedStorage() : data(R_NilValue), token(R_NilValue){} // // ~SharedStorage(){ -// Rcpp_PreciousRelease(token) ; -// data = R_NilValue; -// token = R_NilValue; +// // Rcpp::Rcpp_PreciousRelease(token) ; +// // data = R_NilValue; +// // token = R_NilValue; +// SEXP res = Rf_allocSExp(ENVSXP); +// this->set__(res); // } // // inline void set__(SEXP x){ // if (data != x) { -// data = x; -// Rcpp_PreciousRelease(token); -// token = Rcpp_PreciousPreserve(data); +// try { +// std::string shared_memory_name = "RSharedStorage"; +// boost::interprocess::shared_memory_object::remove(shared_memory_name.c_str()); +// // Create or open the shared memory segment +// boost::interprocess::shared_memory_object shm( +// boost::interprocess::open_or_create, shared_memory_name.c_str(), boost::interprocess::read_write +// ); +// +// // Set the size of the shared memory segment +// shm.truncate(1024); +// +// // Map the shared memory segment into this process's address space +// boost::interprocess::mapped_region region(shm, boost::interprocess::read_write); +// +// // Get a pointer to the shared memory +// unsigned char* shared_memory_ptr = static_cast (region.get_address()); +// data = static_cast (region.get_address()); +// unsigned char* X = (unsigned char*)x; +// memcpy(&X[0], shared_memory_ptr, sizeof(X) * sizeof (unsigned char)); +// +// Rcpp::Rcpp_PreciousRelease(token); +// token = Rcpp::Rcpp_PreciousPreserve(data); +// +// }catch(...){ +// Rcpp::Rcout <<"Error creating shared storage. "< (region.get_address()); + + // Copy the shared environment to shared memory + *sharedMemoryPointer = shared_env; + + UNPROTECT(2); + Rcpp::Rcout<<"Address from write "<(R_ExternalPtrAddr(*sharedMemoryPointer)); +} + +// [[Rcpp::export]] +void CreateSharedEnvironmentNoReturn(const std::string& name){ + // std::string name = "RSharedPtr"; + SEXP res = Rf_allocSExp(ENVSXP); + size_t size_env = sizeof(res); + boost::interprocess::shared_memory_object::remove(name.c_str()); + + SEXP shared_symbol; + PROTECT(shared_symbol = Rf_install("my_shared_env")); + + SEXP shared_env; + PROTECT(shared_env = R_MakeExternalPtr(res, shared_symbol, R_NilValue)); + + const char* segmentName = name.c_str(); // Replace with a suitable name + std::size_t segmentSize = sizeof (SEXP); // Size of the shared environment + + + boost::interprocess::shared_memory_object shm(boost::interprocess::open_or_create, segmentName, boost::interprocess::read_write); + shm.truncate(size_env); + + // Map the shared memory segment + boost::interprocess::mapped_region region(shm, boost::interprocess::read_write); + + // Get a pointer to the memory in the mapped region + SEXP* sharedMemoryPointer = static_cast (region.get_address()); + + // Copy the shared environment to shared memory + *sharedMemoryPointer = shared_env; + + UNPROTECT(2); + // return static_cast(R_ExternalPtrAddr(*sharedMemoryPointer)); +} +// [[Rcpp::export]] +SEXP readSharedEnvironment(const std::string& name){ + Rcpp::Rcout<<"Line 685"< (region.get_address()); + // Rcpp::Rcout<<"Line 701"<(R_ExternalPtrAddr((sharedMemoryPointer))); + Rcpp::Rcout<<"Line 703"<name_m = name; + this->env = readSharedEnvironment(name); + } + + void create(const std::string& name){ + this->name_m = name; + this->env = CreateSharedEnvironment(name); + } + + void load(const std::string& name){ + this->name_m = name; + this->env = readSharedEnvironment(name); + } + + operator Rcpp::Environment(){ + return this->env; + } + + Rcpp::Environment get(){ + return this->env; + } + + std::string name(){ + return this->name_m; + } +}; + // [[Rcpp::export]] void RunProcess(Rcpp::Function fun, Rcpp::Environment env) { @@ -761,7 +922,17 @@ RCPP_EXPOSED_CLASS(Process) .method("write", &Process::write, "Write to the process in stream.") .field("write_log", &Process::write_log, "Write to the process in stream to log.") .field("rank", &Process::rank, "The user assigned rank."); - } + Rcpp::class_("SharedVector") + .constructor() + .constructor() + .method("create", &SharedVector::create, "create shared memory.") + .method("open", &SharedVector::open, "open shared memory.") + .method("set", &SharedVector::set, "set an element at position pos.") + .method("get", &SharedVector::get, "access value at index i") + .method("resize", &SharedVector::resize, "resize the vector") + .method("size", &SharedVector::size, "returns the size of the vector"); + + } // // [[Rcpp::export]] // Process CreateProcess(){ diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 3674fc11..bd4912d9 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -43,6 +43,38 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// CreateSharedEnvironment +SEXP CreateSharedEnvironment(const std::string& name); +RcppExport SEXP _processR_CreateSharedEnvironment(SEXP nameSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const std::string& >::type name(nameSEXP); + rcpp_result_gen = Rcpp::wrap(CreateSharedEnvironment(name)); + return rcpp_result_gen; +END_RCPP +} +// CreateSharedEnvironmentNoReturn +void CreateSharedEnvironmentNoReturn(const std::string& name); +RcppExport SEXP _processR_CreateSharedEnvironmentNoReturn(SEXP nameSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const std::string& >::type name(nameSEXP); + CreateSharedEnvironmentNoReturn(name); + return R_NilValue; +END_RCPP +} +// readSharedEnvironment +SEXP readSharedEnvironment(const std::string& name); +RcppExport SEXP _processR_readSharedEnvironment(SEXP nameSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const std::string& >::type name(nameSEXP); + rcpp_result_gen = Rcpp::wrap(readSharedEnvironment(name)); + return rcpp_result_gen; +END_RCPP +} // RunProcess void RunProcess(Rcpp::Function fun, Rcpp::Environment env); RcppExport SEXP _processR_RunProcess(SEXP funSEXP, SEXP envSEXP) { @@ -105,6 +137,9 @@ static const R_CallMethodDef CallEntries[] = { {"_processR_copyEnvironment", (DL_FUNC) &_processR_copyEnvironment, 1}, {"_processR_writeToSharedMemory", (DL_FUNC) &_processR_writeToSharedMemory, 2}, {"_processR_readEnvironmentFromSharedMemory", (DL_FUNC) &_processR_readEnvironmentFromSharedMemory, 1}, + {"_processR_CreateSharedEnvironment", (DL_FUNC) &_processR_CreateSharedEnvironment, 1}, + {"_processR_CreateSharedEnvironmentNoReturn", (DL_FUNC) &_processR_CreateSharedEnvironmentNoReturn, 1}, + {"_processR_readSharedEnvironment", (DL_FUNC) &_processR_readSharedEnvironment, 1}, {"_processR_RunProcess", (DL_FUNC) &_processR_RunProcess, 2}, {"_processR_RunChild", (DL_FUNC) &_processR_RunChild, 2}, {"_processR_CallRProcess", (DL_FUNC) &_processR_CallRProcess, 2}, diff --git a/test/test_call_R.R b/test/test_call_R.R index 13b27a68..7f05c84b 100644 --- a/test/test_call_R.R +++ b/test/test_call_R.R @@ -10,6 +10,8 @@ rnorm_wrapper<-function(){ return(ret) } +my_env<-processR::CreateSharedEnvironment() +my_env[["my_list"]]<-list() # env__ret = processR::CallRProcess(rnorm_wrapper, environment()) # cat(env__ret[["processR.return"]]) diff --git a/test/test_shared_vector.R b/test/test_shared_vector.R new file mode 100644 index 00000000..277921cf --- /dev/null +++ b/test/test_shared_vector.R @@ -0,0 +1,42 @@ + + +library(processR) +library(Rcpp) +library(RInside) + + +args <- commandArgs() + +rank<-0 +for(i in 1:length(args)){ + if(args[i] == "-sm" && (i+1) <= length(args)){ + print(args[i+1]) + vector_name<<-args[i+1] + } + + if(args[i] == "-rank" && (i+1) <= length(args)){ + print(args[i+1]) + rank_<<- as.integer(args[i+1]) + } + + if(args[i] == "-child"){ + print(args[i+1]) + child<<-TRUE + } + +} + +test<-function(){ + cat("i'm a child\n") + cat("looping through shared_vector at index ") + cat(rank_) + cat("\n") +} + +if(child == TRUE){ +test() +}else{ + + cat("i'm a parent\n") +} + diff --git a/test/test_sm.R b/test/test_sm.R new file mode 100644 index 00000000..cc3bc520 --- /dev/null +++ b/test/test_sm.R @@ -0,0 +1,157 @@ +library(processR) +library(Rcpp) +library(RInside) + +parent <- FALSE +child <- FALSE +rank_ <- 0 +sm_name<- "my_shared_memory" + +begin<-c(0,5) +end<-c(5,10) + +args <- commandArgs() + + +for (i in 1:length(args)) { + if (args[i] == "-parent") { + parent <<- TRUE + } + + + + if (args[i] == "-sm" && (i + 1) <= length(args)) { + # print(args[i + 1]) + + vector_name <<- args[i + 1] + cat("vector_name = ") + cat(vector_name) + cat("\n") + } + + if (args[i] == "-rank" && (i + 1) <= length(args)) { + # print(args[i + 1]) + rank_ <<- as.integer(args[i + 1]) + cat("rank = ") + cat(rank_) + cat("\n") + } + + if (args[i] == "-child") { + child <<- TRUE + } + + +} + +if(child == TRUE){ + cat("rank_ = ") + cat(rank_) + cat("\n") +} + + + +if (parent == TRUE) { + + SMV<- new(processR::SharedVector) + SMV$create(sm_name) + SMV$resize(10) + + for(i in 0:(SMV$size()-1)){ + SMV$set(i,3.1459) + print(SMV$get(i)) + } + + process <- + new(processR::Process, + "Rscript test_sm.R -child -rank 1 -sm MyVector") + process$wait() + cat("child message:\n") + cat(process$get_message()) + + print("parent:") + for(i in 0:(SMV$size()-1)){ + print(SMV$get(i)) + } + +} else{ + + SMV<- new(processR::SharedVector) + SMV$open(sm_name) + for(i in begin[rank_]:(end[rank_]-1)){ + SMV$set(i, SMV$get(i)*2) + } + + + test <- function() { + + print("child:") + for(i in 0:(SMV$size()-1)){ + print(SMV$get(i)) + } + + } + + test() + +} +if(parent == TRUE){ +q() +} +# .GlobalEnv<-processR::CreateSharedEnvironment("global") +#sm_name<-"MySharedEnvironment" +#my_env<-processR::CreateSharedEnvironment(sm_name) +# # address(my_env) +#my_env[["my_list"]]<-list() +#ls(my_env, TRUE) +# +# your_env<-processR::readSharedEnvironment(sm_name) +#ls(your_env,TRUE) +# your_env[["your_list"]]<-list() +# my_env[["test_int"]]<-1 +# ls(my_env, TRUE) +# ls(your_env, TRUE) +# +# my_env[["test_interprocess_write"]]<-c(0,0,0,0) +# cat(my_env[["test_interprocess_write"]]) +# +# # rm(my_env) +# # rm(your_env) +# test<-function(){ +# cat("hi") +# env<-processR::readSharedEnvironment("test_shared_environment") +# +# if(processR.rank == 1){ +# env[["test_interprocess_write"]][1]<-1 +# env[["test_interprocess_write"]][2]<-1 +# }else{ +# env[["test_interprocess_write"]][3]<-2 +# env[["test_interprocess_write"]][4]<-2 +# } +# } +# +# +# +# #create a pool child processes +# pool <- processR::CreateProcessPool(1)#list() +# +# for (i in 1:length(pool)){#processR::HardwareConcurrency()) { +# #creat a new child +# ###pool[[i]] <- new(processR::Process) +# #pass the entry function, environment, and child rank +# pool[[i]]$start(test, environment(), i) +# print(pool[[i]]$pid() ) +# } +# +# print("waiting...") +# for (j in 1:length(pool)) { +# #wait for the children to finish +# pool[[j]]$wait() +# } +# # +# # env<-processR::readSharedEnvironment("test_shared_environment") +# # +# # cat(env[["test_interprocess_write"]]) +# # +# #