I'm trying to transform this code that uses fork() to thread. Because i need the variable value to change.
Code using fork():
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int value = 5;
int main(){
pid_t pid;
pid = fork();
if(pid == 0){ //child process
printf("Entrei no filho! \n");
value += 15;
return 0;
}
else if(pid > 0){ //parent process
wait(NULL);
printf("PARENT: value = %d\n", value);
return 0;
}}
The final value is 5
My attempt:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int main(int argc, char *argv[]){
pthread_t thread1, thread2;
char *msg1 = "First thread";
char *msg2 = "Second thread";
int value = 5;
pthread_create(thread1, NULL, if1, (void *) msg1);
pthread_create(thread2, NULL, if2, (void *) msg2);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void *if1(){
value += 15;
return NULL;
}
void *if2(){
printf("Final value: %d",value);
return NULL;
}
The final value has to be 20 using threads
Related
This question already has answers here:
How to use shared memory with Linux in C
(5 answers)
Closed 4 years ago.
This is essentially what I want to do, but the outputs are junk data. What are some of the different options I have for making the child's array visible from inside the parent process?
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int foo[3]; //initialize array
pid_t pid;
pid = fork(); //create child thread
if (pid == 0) { //child:
foo[0] = 0; foo[1] = 1; foo[2] = 2; //populate array
}
else { //parent:
wait(NULL); //wait for child to finish
printf("%d %d %d", foo[0], foo[1], foo[2]); //print contents of array
}
return 0;
}
Using mmap you can create a shared memory block in your parent process. This is a basic example removing error checking for brevity.
You want to sure the proper protections and flags are set for your needs. Then hand off the address returned by mmap to your child process.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#define LIMIT_MAP 5
void child_worker(void *map)
{
int map_value = -1;
int idx = 0;
while (map_value != LIMIT_MAP) {
map_value = *((int *) map + (idx * sizeof(int)));
printf("Map value: %d\n", map_value);
idx++;
sleep(2);
}
}
int main(int argc, char *argv[])
{
printf("Starting Parent Process...\n");
long page_size = sysconf(_SC_PAGESIZE);
void *memory_map = mmap(0, page_size, PROT_WRITE | PROT_READ,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
printf("Memory map created: <%p>\n", memory_map);
pid_t pid = fork();
if (pid == 0) {
sleep(1);
printf("Starting child process\n");
child_worker(memory_map);
printf("Exiting child process...\n");
return 0;
} else {
printf("Continuing in parent process\n");
int set_values[5] = { 1, 2, 3, 4, 5 };
for (int i=0; i < 5; i++) {
printf("Setting value: %d\n", set_values[i]);
*((int *) memory_map + (sizeof(int) * i)) = set_values[i];
sleep(1);
}
waitpid(pid, NULL, 0);
printf("Child process is finished!\n");
}
return 0;
}
If fork isn't a requirement and your platform allows for it, pthread is one option. Depending on how your array is being operated on, create a thread pool passing each worker thread a copy of your array.
This is a contrived example but maybe you can pull something from it:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#define THREAD_COUNT 3
#define ITER_LIMIT 7
struct worker_params {
int idx;
int max;
bool done;
double *data;
double condition;
};
void *worker(void *arg)
{
struct worker_params *wp = (struct worker_params *) arg;
int count = 0;
while ( 1 ) {
wp->data[wp->idx] = drand48();
if (wp->max == count)
wp->done = true;
sleep(1);
count++;
}
return NULL;
}
int main(int argc, char *argv[])
{
double data[THREAD_COUNT] = { 0.0 };
pthread_t worker_1, worker_2, worker_3;
pthread_t worker_threads[] = { worker_1, worker_2, worker_3 };
struct worker_params wps[] = {
{ .idx=0, .condition=0.1, .data=data, .done=0 },
{ .idx=1, .condition=0.2, .data=data, .done=0 },
{ .idx=2, .condition=0.3, .data=data, .done=0},
};
for (int i=0; i < THREAD_COUNT; i++) {
wps[i].max = (rand() % ITER_LIMIT) + 2;
pthread_create(&worker_threads[i], NULL, worker, (void *) &wps[i]);
}
// Continue on main execution thread
int running = 1;
while ( running ) {
for (int i=0; i < THREAD_COUNT; i++) {
if (wps[i].done) {
printf("Limit hit in worker <%d>\n", i + 1);
running = 0;
break;
}
printf("Data in worker <%d> :: %g\n", i + 1, wps[i].data[i]);
}
sleep(1);
}
return 0;
}
The code doesn't work and it goes in loop. I think the error is in the gestore method, that is a handler for SIGCHLD signals. This is the first time I use a handler to capture SIGCHLD signals.
This program continue to casually extracts from 0 to argv[1] until a number appears argv[1] times.
If it's not clear you can test my old program that I put at the end of question.
Can you help me finding the error?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int a;
void gestore(int segnale);
int main(int argc, char * argv[]){
int n = atoi(argv[1]), i, pid;
int * vec;
vec = malloc((n+1)*sizeof(*vec));
memset (vec, 0, sizeof(*vec));
char * newargv[] = {argv[0], argv[1] , NULL};
for(i = 0; i < n; i++){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
signal(SIGCHLD, gestore);
vec[WEXITSTATUS(a)]++;
}
while(vec[i] != n){
for(i = 1; i < n+1 && vec[i] != n; i++){
if(vec[i] != 0){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
signal(SIGCHLD, gestore);
vec[WEXITSTATUS(a)]++;
}
}
}
printf("The value %d is appeared %d times!\n", i, vec[i]);
while (wait(&a) != -1);
free(vec);
}
void gestore(int segnale){
signal(segnale, SIG_IGN);
waitpid(WAIT_ANY, &a, WNOHANG);
signal(segnale, gestore);
}
My goal was to modify my old program (that works) changing the way I capture the exit status of childs. From syncronically with "wait" to asyncronically with a gestore method that handle SIGCHLD signals.
This is my old program:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char * argv[]){
int n = atoi(argv[1]), a, i, pid;
int * vec;
vec = malloc((n+1)*sizeof(*vec));
memset (vec, 0, sizeof(*vec));
char * newargv[] = {argv[0], argv[1] , NULL};
for(i = 0; i < n; i++){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
wait(&a);
vec[WEXITSTATUS(a)]++;
}
while(vec[i] != n){
for(i = 1; i < n+1 && vec[i] != n; i++){
if(vec[i] != 0){
pid = fork();
if (pid == 0)
execve("./throw-dice", newargv, NULL);
wait(&a);
vec[WEXITSTATUS(a)]++;
}
}
}
printf("The value %d is appeared %d times\n", i, vec[i]);
while (wait(&a) != -1);
free(vec);
}
//throw-dice.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char * argv[]) {
int n, val;
// Must have an argument
if (argc < 2) {
exit(-1);
}
// the 1st argument must be a positive number
if ((n = atoi(argv[1])) <= 0) {
exit(-1);
}
// sleep(1); // sleep a bit
srand(getpid()); // initialize the random seed with PID
val = rand() % n + 1;
printf("(PID=%d): got number %d\n", getpid(), val);
exit(val);
}
I want to create n processes running in parallel and have them lock a mutex, increment a counter, and then unlock and exit.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
int status = 0;
pthread_mutex_init(&mutex, NULL);
pid_t pid = 1;
static int *x;
x = mmap(NULL, sizeof *x, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*x = 0;
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0)
pid = fork();
}
if (pid == 0) {
pthread_mutex_lock(&mutex);
*x = *x + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), *x);
pthread_mutex_unlock(&mutex);
exit(0);
}
wait(&status);
printf("[PRNT] PID: %d X: %d\n", getpid(), *x);
munmap(x, sizeof *x);
return 0;
}
./procs 10000 however does not return with x=10000
I think this is because the mutex isn't shared between the processes, but what's the correct way to share the mutex?
Here's a port of my example in the comment using pthread_mutex. First time I've done this, but seems to work:
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <pthread.h>
typedef struct
{
bool done;
pthread_mutex_t mutex;
} shared_data;
static shared_data* data = NULL;
void initialise_shared()
{
// place our shared data in shared memory
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_ANONYMOUS;
data = mmap(NULL, sizeof(shared_data), prot, flags, -1, 0);
assert(data);
data->done = false;
// initialise mutex so it works properly in shared memory
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&data->mutex, &attr);
}
void run_child()
{
while (true)
{
puts("child waiting. .. ");
usleep(500000);
pthread_mutex_lock(&data->mutex);
if (data->done) {
pthread_mutex_unlock(&data->mutex);
puts("got done!");
break;
}
pthread_mutex_unlock(&data->mutex);
}
puts("child exiting ..");
}
void run_parent(pid_t pid)
{
puts("parent sleeping ..");
sleep(2);
puts("setting done ..");
pthread_mutex_lock(&data->mutex);
data->done = true;
pthread_mutex_unlock(&data->mutex);
waitpid(pid, NULL, NULL);
puts("parent exiting ..");
}
int main(int argc, char** argv)
{
initialise_shared();
pid_t pid = fork();
if (!pid) {
run_child();
}
else {
run_parent(pid);
}
munmap(data, sizeof(data));
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
typedef struct {
pthread_mutex_t mutex;
int data;
}MUTEX_N_DATA;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
bool wait = true;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pid_t pid = 1;
MUTEX_N_DATA *x;
x = mmap(NULL, sizeof(MUTEX_N_DATA), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
x->data = 0;
pthread_mutex_init(&x->mutex, &attr);
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0) {
pid = fork();
printf("Created Child %d \n",pid);
}
}
if (pid == 0) {
pthread_mutex_lock(&x->mutex);
x->data = x->data + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), x->data);
pthread_mutex_unlock(&x->mutex);
exit(0);
}
while(wait){
pthread_mutex_lock(&x->mutex);
if(x->data == n){
wait = false;
}
pthread_mutex_unlock(&x->mutex);
usleep(100000);
}
printf("[PRNT] PID: %d X: %d\n", getpid(), x->data);
munmap(x, sizeof *x);
return 0;
}
The wait() waits only until one of the child exits. with following changes it works.
mutex attribute set to shared & moved to mmap memory.
parent waiting for the count to reach the number of childrens.
https://man7.org/linux/man-pages/man2/fork.2.html
https://man7.org/linux/man-pages/man2/wait.2.html
I have to write a program in C that uses processes, not threads (I'm writing in UNIX):
the father generate 7 children.
every child generate a random integer and begin an empty for statement from 0 to that random int.
at the end, the father calls wait and print the pid of the last but one process that has terminated.
this is what I'm trying:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/ipc.h>
int main(){
int n = 7;
int i,r, random;
pid_t pid;
pid_t pid_padre;
int *shared_memory;
int segment_id;
int size = 1024;
int ciclo;
pid_padre = getpid();
printf("Inizio programma:\n");
printf("Processo Padre: [%d]\n", pid_padre);
segment_id = shmget(IPC_PRIVATE, size, S_IRUSR | S_IWUSR);
shared_memory = shmat(segment_id, NULL, 0);
for(i=0;i<n;i++) {
shared_memory[i] = 0;
}
for(i=0;i<n;i++) {
pid =fork();
if (pid == 0) {
random = rand();
for(ciclo=0; ciclo<random; ciclo++);
for (r=0; r<n; r++) {
if (shared_memory[r] == 0) {
//printf("figlio %d\n",getpid() );
//shared_memory[r] = (int)getpid();
break;
}
}
break;
}
}
if (getpid() == pid_padre) {
wait(NULL);
//sleep(3);
for(i=0;i<n;i++) {
printf("array, figlio %d, pid \n",i , shared_memory[i]);
}
shmdt(shared_memory);
shmctl(segment_id, IPC_RMID, NULL);
}
return 0;
}
edit: what's wrong in my code: at the end, it does print nothing instead of pids, it prints
"array, figlio 1, pid "
instead of "array, figlio 1, pid 3898" for example
This will probably require some looking into, but my question is very simple:
Why is numPassenger always 0 in the parentHandler2() function?
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <sys/time.h>
#include <math.h>
int getRand()
{
return (rand() % 5001);
}
//////////GLOBAL//////////
const int CAPACITY = 100;
const int MEMSIZE = 1024;
char* sharedmem;
pid_t pid;
int numPassenger;
int numTram;
//////////GLOBAL//////////
//handles SIGALRM, generates passengers, sends SIGUSR1
void parentHandler1()
{
numPassenger = getRand();
sprintf(sharedmem, "%d", numPassenger);
kill(getpid(), SIGUSR1);
}
//handles SIGUSR1, calculates number of trams needed, sends SIGUSR2
void childHandler()
{
double n = atoi(sharedmem);
numTram = (ceil(n/100));
sprintf(sharedmem, "%d", numTram);
kill(pid, SIGUSR2);
}
//outputs
void parentHandler2()
{
int n = atoi(sharedmem);
printf("Passengers: %d, Trams: %d\n", numPassenger, n);
}
int main (int argc, char* argv[])
{
srand(time(0));
key_t key;
int shmemaddr;
//shared memory
key=ftok(argv[0],1);
shmemaddr=shmget(key,MEMSIZE,IPC_CREAT|S_IRUSR|S_IWUSR);
sharedmem = shmat(shmemaddr,NULL,0);
pid = fork();
if ( pid > 0 )
{
//timer
struct itimerval timer;
timer.it_value.tv_sec = 3;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 3;
timer.it_interval.tv_usec = 0;
setitimer (ITIMER_REAL, &timer, NULL);
signal(SIGALRM, parentHandler1);
signal(SIGUSR1, childHandler);
}
else if ( pid == 0 )
{
signal(SIGUSR2, parentHandler2);
}
//not so busy waiting
while(1) sleep(1);
return 0;
}
https://gist.github.com/4299915
Fork creates a new copy of the current process. Global variables aren't shared between processes. The only memory that is shared between your two processes is the memory returned by shmget. The value of numPassenger is never set in the child process.