C++ Execute one child process iteration after another process - c++

I want to create two child processes with some iterations in them so that iteration l in process X always executes after iteration l+1 in process Y.
#include <stdio.h>
#include <unistd.h>
#include <bits/stdc++.h>
#include <sys/wait.h>
#include <semaphore.h>
using namespace std;
sem_t mut;
int x = 2;
int main()
{
int cpX = fork();
sem_init(&mut, 1, 1);
if (cpX == 0)
{
//child A code
for (int i = 0; i < 10; i++)
{
sem_wait(&mut);
cout << "Inside X:" << getpid() << ", " << i << '\n';
sleep(rand() % 5);
}
exit(0);
}
else
{
int cpY = fork();
if (cpY == 0)
{
//child B code
for (int i = 0; i < 10; i++)
{
cout << "Inside Y:" << getpid() << ", " << i << '\n';
sleep(rand() % 5);
sem_post(&mut);
}
//sem_wait(&mut);
exit(0);
}
else
{
//sleep(50);
//wait(NULL);
//wait(NULL);
exit(0);
// wait(NULL);
}
}
}
However here, X executes once, and then Y starts executing and X never executes again. Why is this happening?

The parent/child during a fork is doing a copy so they are not referring to the same semaphore object. Hence, mut is not shared as what you assumed. Your snippet is near correct you just need to do minor changes to work as you expect.
Since you are using an unnamed semaphore, you need to instantiate the semaphore object in a shared area:
#include <sys/mman.h>
sem_t *mut = (sem_t*)mmap(NULL, sizeof(*mut), PROT_READ |PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS, -1, 0);
sem_init(mut, 1, 1);
With this minor adjustments, your snippet above now works as expected as they are now referring to the same semaphore object.
Also, some tips: sem_post is an unblocking call, whereas sem_wait is a blocking call. You need to be also aware that a signal sent by sem_post could get lost when nobody is waiting on the semaphore during that moment.
The best reference of this kinds of things is Unix Network Programming: Interprocess Communication by Richard Stevens

Related

Mutex does not work as expected

I have used mutex in inherited classes but seems it does not work as I expected with threads. Please have a look at below code:
#include <iostream>
#include <cstdlib>
#include <pthread.h>
// mutex::lock/unlock
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::thread
#include <mutex> // std::mutex
typedef unsigned int UINT32t;
typedef int INT32t;
using namespace std;
class Abstract {
protected:
std::mutex mtx;
};
class Derived: public Abstract
{
public:
void* write( void* result)
{
UINT32t error[1];
UINT32t data = 34;
INT32t length = 0;
static INT32t counter = 0;
cout << "\t before Locking ..." << " in thread" << endl;
mtx.lock();
//critical section
cout << "\t After Create " << ++ counter << " device in thread" << endl;
std::this_thread::sleep_for(1s);
mtx.unlock();
cout << "\t deallocated " << counter << " device in thread" << endl;
pthread_exit(result);
}
};
void* threadTest1( void* result)
{
Derived dev;
dev.write(nullptr);
}
int main()
{
unsigned char byData[1024] = {0};
ssize_t len;
void *status = 0, *status2 = 0;
int result = 0, result2 = 0;
pthread_t pth, pth2;
pthread_create(&pth, NULL, threadTest1, &result);
pthread_create(&pth2, NULL, threadTest1, &result2);
//wait for all kids to complete
pthread_join(pth, &status);
pthread_join(pth2, &status2);
if (status != 0) {
printf("result : %d\n",result);
} else {
printf("thread failed\n");
}
if (status2 != 0) {
printf("result2 : %d\n",result2);
} else {
printf("thread2 failed\n");
}
return -1;
}
so the result is:
*Four or five arguments expected.
before Locking ... in thread
After Create 1 device in thread
before Locking ... in thread
After Create 2 device in thread
deallocated 2 device in thread
deallocated 2 device in thread
thread failed
thread2 failed
*
So here we can see that second thread comes to critical section before mutex was deallocated.
The string "After Create 2 device in thread" says about that.
If it comes to critical section before mutex is deallocated it means mutex works wrong.
If you have any thoughts please share.
thanks
The mutex itself is (probably) working fine (I'd recommend you to use std::lock_guard though), but both threads create their own Derived object, hence, they don't use the same mutex.
Edit: tkausl's answer is correct -- however, even if you switch to using a global mutex, the output may not change because of the detail in my answer so I'm leaving it here. In other words, there are two reasons why the output may not be what you expect, and you need to fix both.
Note in particular these two lines:
mtx.unlock();
cout << "\t deallocated " << counter << " device in thread" << endl;
You seem to be under the impression that these two lines will be run one right after the other, but there is no guarantee that this will happen in a preemptive multithreading environment. What can happen instead is that right after mtx.unlock() there could be a context switch to the other thread.
In other words, the second thread is waiting for the mutex to unlock, but the first thread isn't printing the "deallocated" message before the second thread preempts it.
The simplest way to get the output you expect would be to swap the order of these two lines.
You shall declare your mutex as a global variable and initiate it before calling pthread_create. You created two threads using pthread_create and both of them create their own mutex so there is absolutely no synchronization between them.

Assertion when trying to a use a Boost.Interprocess message queue across a bunch of processes

I have the following reduced program that spins up a bunch of child processes and then uses a boost::interprocess::message_queue to send a message to each one. This works when number of processes is small (about 4 on my machine) but as that number rises I get the following message:
head (81473): "./a.out"
Assertion failed: (res == 0), function do_wait, file /usr/local/include/boost/interprocess/sync/posix/condition.hpp, line 175.
I'm guessing it's a problem with my synchronisation.. have I done something wrong or is the boost::interprocess::scoped_lock not enough?
My program is here:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/process.hpp>
#include <iostream>
auto main(int argc, char **argv) -> int
{
namespace ip = boost::interprocess;
boost::filesystem::path self{argv[0]};
if (argc == 1) {
std::cout << "head (" << ::getpid() << "): " << self << std::endl;
// create a message queue.
ip::message_queue::remove("work_queue");
ip::message_queue tasks{ip::create_only, "work_queue", 100, sizeof(int)};
// mutex for writing to the queue.
ip::interprocess_mutex mutex{};
// spawn off a bunch of processes.
const auto cores{5 * std::thread::hardware_concurrency()};
std::vector<boost::process::child> workers{};
for (auto i = 0; i < cores; ++i) {
workers.emplace_back(self, "child");
}
// send message to each core.
for (auto i = 0; i < cores; ++i) {
ip::scoped_lock<decltype(mutex)> lock{mutex};
tasks.send(&i, sizeof(i), 0);
}
// wait for each process to finish.
for (auto &worker : workers) {
worker.wait();
}
} else if (argc == 2 && std::strcmp(argv[1], "child") == 0) {
// connect to message queue.
ip::message_queue tasks{ip::open_only, "work_queue"};
// mutex for reading from the queue.
ip::interprocess_mutex mutex{};
unsigned int priority;
ip::message_queue::size_type recvd_size;
{
ip::scoped_lock<decltype(mutex)> lock{mutex};
int number;
tasks.receive(&number, sizeof(number), recvd_size, priority);
std::cout << "child (" << ::getpid() << "): " << self << ", received: " << number << std::endl;
}
}
return 0;
}
You create an interprocess_mutex instance on the stack. So each process has it's own mutex and locking it does not synchronize anything. You need to create a shared memory region, place mutex there and then open the same shared memory region in child process to access the mutex created by parent process.

C++ multi thread programming with timer

I am new to multi thread programming, so this question might seem a little silly, but I really need to work this out so I can apply it to my project (which is way more complicated).
Follow is my code, I am trying to have 2 threads (parent and child) to update the same shared timer as they execute and stop when the timer reaches a specific limit.
But when I compile and execute this follow piece of code, there are 2 different outcomes: 1. child prints "done by child at 200000" but the program does not exit; 2. after child prints "done by child at 200000" and exits, parent keeps executing, prints a couple of dozen lines of "parent doing work" and "parent at 190000", then prints "done by parent at 200000" and the program exits properly.
The behavior I want is for whichever thread that updates the timer, hits the limit and exits, the other thread should stop executing and exit as well. I think I might be missing something trivial here, but I've tried changing the code in many ways and nothing I tried seem to work. Any help will be much appreciated :)
#include <iostream>
#include <unistd.h>
#include <mutex>
#include <time.h>
using namespace std;
mutex mtx;
int main () {
int rc;
volatile int done = 0;
clock_t start = clock();
volatile clock_t now;
rc = fork();
if (rc == 0) { //child
while (true) {
cout << "child doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
mtx.unlock();
break;
}
cout << "child at " << now << endl;
mtx.unlock();
}
_exit(0);
}
else { // parent
while (true) {
cout << "parent doing work" << endl;
mtx.lock();
now = clock() - start;
if (done) {
mtx.unlock();
break;
}
if (now >= 200000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
mtx.unlock();
break;
}
cout << "parent at " << now << endl;
mtx.unlock();
}
}
return 0;
}
Multi-processes
Your code is multi-processes and not multi-threading: fork() will create a new separate process by duplicating the calling process.
The consequence: At the moment of the duplication, all the variables contain the same value in both processes. But each process has its own copy, so a variable modified in the parent will not be updated in the child's address space an vice-versa.
If you want to share variables between processes, you should have a look at this SO question
Multithread
For real multithreading, you should use std::thread. And forget about volatile, because it's not thread safe. Use <atomic> instead, as explained in this awesome video.
Here a first try:
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <time.h>
using namespace std;
void child (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "child doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by child at " << now << endl;
}
cout << "child at " << now << endl;
this_thread::yield();
}
}
void parent (atomic<int>& done, atomic<clock_t>& now, clock_t start)
{
while (!done) {
cout << "parent doing work" << endl;
now = clock() - start;
if (now >= 2000 && !done) {
done = 1;
cout << "done by parent at " << now << endl;
}
cout << "parent at " << now << endl;
this_thread::yield();
}
}
int main () {
atomic<int> done{0};
clock_t start = clock();
atomic<clock_t> now;
thread t(child, std::ref(done), std::ref(now), start); // attention, without ref, you get clones
parent (done, now, start);
t.join();
return 0;
}
Note that you don't need to protect atomic accesses with a mutex, and that if you want to do, lock_guard would be recommended alternative.
This example is of course rather weak, because if you test an atomic variable if the if-condition, it's value might already have changed when entering the if-block. This doesn't cause a problem in your logic where "done" means "done". But if you'd need a more cauthious approach,
compare_exchange_weak() or compare_exchange_strong() could help further.

Why does this code stop running when it hits the pipe?

When this program runs it goes through the loop in the parent then switches to the child when it writes to the pipe. In the child the pipe that reads just causes the program to stop.
Current example output:
Parent 4741 14087 (only this line when 5 more lines are expected)
Expected output(with randomly generated numbers):
Parent 4741 14087
Child 4740 47082
Parent 4741 11345
Child 4740 99017
Parent 4741 96744
Child 4740 98653
(when given the variable 3 and the last number is a randomly generated number)
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <ctime>
using namespace std;
int main (int argc, char *argv[]) {
int pid = fork(), temp, randNum, count, pipeName[2], pipeName2[2];
string conver;
pipe(pipeName);
conver = argv[1];
temp = atoi(conver.c_str());
char letter;
if (pid == 0) { //child
srand((unsigned)time(NULL) * getpid() );
//closing unused pipes
close(pipeName2[1]);
close(pipeName[0]);
//loop to switch between processes
for(int i=0; i<temp; i++) {
count = read(pipeName2[0], &letter, 20);
randNum = rand();
cout << "Child " << getpid() << " " << randNum << endl;
write(pipeName[1], "x", 1);
}
close(pipeName2[0]);
close(pipeName[1]);
}
else { //parent
srand((unsigned)time(NULL) * getpid() );
pipe(pipeName2);
//closing unused pipes
close(pipeName2[0]);
close(pipeName[1]);
//loop to switch between processes
for(int i=0; i<temp; i++) {
if(i != 0)
count = read(pipeName[0], &letter, 20);
randNum = rand();
cout << "Parent " << getpid() << " " << randNum << endl;
write(pipeName2[1], "x", 1);
}
close(pipeName[0]);
close(pipeName2[1]);
}
}
The program ends when it hits the read from pipe line in the child.
Your principal mistake is fork()ing before you initialize the pipes. Both parent and child thus have their own private (not shared via fd inheritance) pipe pair named pipeName, and only the parent initializes pipeName2 with pipe fds.
For the parent, there's simply no data to read behind pipeName[0]. For the child ... who knows what fd it is writing to in pipeName2[1]? If you're lucky that fails with EBADF.
So, first pipe() twice, and then fork(), and see if that improves things.

Understanding the posix interprocess semaphore

According to my understanding, a semaphore should be usable across related processes without it being placed in shared memory. If so, why does the following code deadlock?
#include <iostream>
#include <semaphore.h>
#include <sys/wait.h>
using namespace std;
static int MAX = 100;
int main(int argc, char* argv[]) {
int retval;
sem_t mutex;
cout << sem_init(&mutex, 1, 0) << endl;
pid_t pid = fork();
if (0 == pid) {
// sem_wait(&mutex);
cout << endl;
for (int i = 0; i < MAX; i++) {
cout << i << ",";
}
cout << endl;
sem_post(&mutex);
} else if(pid > 0) {
sem_wait(&mutex);
cout << endl;
for (int i = 0; i < MAX; i++) {
cout << i << ",";
}
cout << endl;
// sem_post(&mutex);
wait(&retval);
} else {
cerr << "fork error" << endl;
return 1;
}
// sem_destroy(&mutex);
return 0;
}
When I run this on Gentoo/Ubuntu Linux, the parent hangs. Apparently, it did not receive the post by child. Uncommenting sem_destroy won't do any good. Am I missing something?
Update 1:
This code works
mutex = (sem_t *) mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0);
if (!mutex) {
perror("out of memory\n");
exit(1);
}
Thanks,
Nilesh.
The wording in the manual page is kind of ambiguous.
If pshared is nonzero, then the semaphore is shared between processes,
and should be located in a region of shared memory.
Since a child created by fork(2) inherits its parent's memory
mappings, it can also access the semaphore.
Yes, but it still has to be in a shared region. Otherwise the memory simply gets copied with the usual CoW and that's that.
You can solve this in at least two ways:
Use sem_open("my_sem", ...)
Use shm_open and mmap to create a shared region
An excellent article on this topic, for future passers-by:
http://blog.superpat.com/2010/07/14/semaphores-on-linux-sem_init-vs-sem_open/