I'm currently being introduced to the concept of threading programs, and have been given an assignment to simulate a stockmarket using threads and semaphores. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <semaphore.h>
#include <pthread.h>
#define NUM_WRITERS 5
#define NUM_READERS 5
#define STOCKLIST_SIZE 10
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t stop_writers;
typedef struct
{ int readers;
int slots[STOCKLIST_SIZE];
} mem_structure;
int id[NUM_READERS + NUM_WRITERS];
mem_structure *stocklist;
pthread_t thr[NUM_WRITERS + NUM_READERS];
void init(){
sem_init(&stop_writers, 0, 1);
}
void cleanup(int signo) // clean up resources by pressing Ctrl-C
{ sem_destroy(&stop_writers);
printf("Closing...\n");
exit(0);
}
void write_stock(int n_writer)
{
int stock = (int)(rand()%STOCKLIST_SIZE);
int stock_value = 1 + (int)(100.0 * rand()/(RAND_MAX + 1.0));
stocklist->slots[stock] = stock_value;
fprintf(stderr, "Stock %d updated by BROKER %d to %d\n", stock, n_writer, stock_value);
}
void* writer(void* id){
int my_id = *((int*) id);
int i = my_id;
while (1)
{
pthread_mutex_lock(&mutex);
sem_wait(&stop_writers);
write_stock(i);
pthread_mutex_unlock(&mutex);
sem_post(&stop_writers);
sleep(1);
++i;
}
}
void read_stock(int pos, int n_reader){
fprintf(stderr, "Stock %d read by client %d = %d.\n", pos, n_reader, stocklist->slots[pos]);
}
void* reader(void* id){
int my_id = *((int*) id);
int i = my_id;
while (1)
{ sem_wait(&stop_writers);
read_stock((int)(rand()%STOCKLIST_SIZE), i);
sem_post(&stop_writers);
sleep(1 + (int) (3.0 * rand() / (RAND_MAX + 1.0)));
++i;
}
}
void monitor() // main process monitors the reception of Ctrl-C
{
struct sigaction act;
act.sa_handler = cleanup;
act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigaction(SIGINT, &act, NULL) == -1))
perror("Failed to set SIGINT to handle Ctrl-C");
while(1){
sleep(5);
printf("Still working...\n");
}
exit(0);
}
int main(void)
{ int i, j;
init();
for (i = 0; i < NUM_WRITERS; ++i){
id[i] = i;
pthread_create(&thr[i], NULL, writer, &id[i]);}
for (j = i; j < NUM_READERS; ++j){
id[j] = j;
pthread_create(&thr[j], NULL, reader, &id[j]);}
stocklist->readers = 0;
pthread_exit(NULL);
monitor();
return 0;
}
This is giving me a segmentation fault pretty much as soon as main() begins, with the creation of a thread... Since it's not code that I've created from root, I'm having trouble backtracing the error and fixing it - it would be great if there was someone who could take a look and maybe give me some hints
Thank you!
EDIT
Fixed the problem, thanks to your help :)
I initialized stocklist on init(),
void init(){
sem_init(&stop_writers, 0, 1);
stocklist = (mem_structure*)malloc(sizeof(mem_structure));
}
And changed the second cicle in main(),
for (j = i; j < NUM_READERS+NUM_WRITERS; ++j){
id[j] = j;
pthread_create(&thr[j], NULL, reader, &id[j]);}
Thanks
Here's what I did to track down the problem:
gcc -g program.c -lpthread
gdb a.out
run
Output:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7feeb70 (LWP 23060)]
0x08048834 in write_stock (n_writer=0) at program.c:44
44 stocklist->slots[stock] = stock_value;
Looks like the problem is here:
stocklist->slots[stock] = stock_value;
Related
I am trying to have a multithread program that work with struct and semaphore.
I am not sure how to pass those values. Therefore I decided to pass my struct by reference and put my semaphore as a global variable.
What I am trying to do is to make two threads count to 20
(where one would be t1 = 0, 2 , 4 ,6 ... 20 and t2 = 1, 3 , ... , 19)
Here is what I have so far:
#include <fcntl.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#define SEM_sem;
#define MaxVal 20;
typedef struct {
int startVal;
int maxVal;
} countStruct;
sem_t *sem;
void *t1(void *param) {
countStruct *counting;
counting = (countStruct *) param;
int i = counting->startVal;
while(i <= counting->maxVal) {
printf("%d\n",i);
i = i + 2;
sem_post(sem);
sem_wait(sem);
}
pthread_exit(0);
}
void *t2(void *param) {
countStruct *counting;
counting = (countStruct *) param;
int i = counting->startVal;
while(i <= counting->maxVal) {
printf("%d\n",i);
i = i + 2;
sem_post(sem);
sem_wait(sem);
}
pthread_exit(0);
}
int main() {
sem = sem_open(SEM_sem, O_CREAT | O_EXCL, 0666, 0);
if (sem == SEM_FAILED) {
printf("sem_open() failed\n");
sem_unlink(SEM_mpoulinl);
return(8);
}
pthread_attr_t attr;
pthread_t tid1, tid2
countStruct array_struct[3];
int i = 0;
for(i ; i < 2 ; i++) {
array_struct[i].startVal = i;
array_struct[i].maxVal = MaxVal;
}
pthread_create(&tid1, NULL, t1, (void*)&array_struct[0]);
sleep(1);
pthread_create(&tid2, NULL, t=2, (void*)&array_struct[1]);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
sem_close(sem);
sem_unlink(SEM_mpoulinl);
return(0);
}
Unfortunately my code print t1 then t2.
Why is it not working?
is it because my semaphore is global?
I tested taking out sem_post(sem) sem_wait(sem) and the code still work, therefore those two things does not seem to work or am I not using it appropriately?
Thank you!
I'm a novice in C and trying to learn Multi Threading.
I played aroud with a C program counting to 100000 with 2 threads and outputing to text.
However, my program seem to have seg. fault.
I cannot figure it out.
Please Help :)
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define COUNT_TO 100000
#define MAX_CORES 2
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
long long i = 0;
void *start_counting(FILE *out)
{
//lock
pthread_mutex_lock(&mutex);
while (i < COUNT_TO)
{
++i;
printf("i = %lld\n", i);
fprintf(out,"i = %lld\n", i);
}
//lock
pthread_mutex_unlock(&mutex);
}
int main(void)
{
int i = 0;
FILE *out;
out = fopen("output.txt","w");
// create a thread group the size of MAX_CORES
pthread_t *thread_group = malloc(sizeof(pthread_t) * MAX_CORES);
// start all threads to begin work
for (i = 0; i < MAX_CORES; ++i)
{
pthread_create(&thread_group[i], NULL, start_counting(out), NULL);
}
// wait for all threads to finish
for (i = 0; i < MAX_CORES; ++i)
{
pthread_join(thread_group[i], NULL);
}
fclose(out);
return EXIT_SUCCESS;
}
You have a error in this call:
pthread_create(&thread_group[i], NULL, start_counting(out), NULL);
It should be:
pthread_create(&thread_group[i], NULL, start_counting, out);
Please refer to the manual at https://man7.org/linux/man-pages/man3/pthread_create.3.html
So I have three files: Pellets.c, Fish.c, and SwimMill.c. SwimMill calls Pellets and Fish, which should fork. However, when I try to fork Pellets, i get an error saying "Pellet fork failed: Bad Address". Anyone know what the problem is?
include.h
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#define SHM_SIZE 1000
int shmid;
int *shm;
pid_t fish;
pid_t pellet;
void attachSharedMemory() {
key_t key = ftok("SwimMill.c", 'b'); //generate random key
shmid = shmget(key, SHM_SIZE, IPC_CREAT|0666);
shm = shmat(shmid, NULL, 0);
}
SwimMill.c
// Uses both fish and pellets, 30 seconds, then print it out
// Create pellets at random intervals, from 0x80
// Eating --> Get rid of most significant bit
// Use shared memory for fish and pellet position only
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "include.h"
#define SHM_SIZE 1000
void printGrid(int*);
void handler(int);
void killProgram(pid_t, pid_t, int*, int);
pid_t fish;
pid_t pellet;
int main(int argc, char* argv[]) {
int timer = 0;
attachSharedMemory(); // from include.h
signal(SIGINT, handler);
// Initializing the shared memory to prevent segmentation fault
// for (int i = 0; i < SHM_SIZE; i++){
// shm[i] = -1;
// }
srand(time(NULL));
fish = fork();
if (fish == -1) {
perror("Fish fork failed1");
exit(1);
} else if (fish == 0) {
execv("Fish", argv);
perror("Fish exec failed");
exit(1);
}
while(timer <= 30){
pellet = fork();
if (pellet == -1) {
perror("Pellet Fork failed1");
exit(1);
} else if (pellet == 0) {
execv("Pellets", argv);
perror("Pellets Fork failed");
exit(1);
}
printGrid(shm);
sleep(1);
printf("Timer: %d\n", timer);
timer++;
}
killProgram(fish, pellet, shm, shmid);
getchar(); // Pause consol
return 0;
}
void printGrid(int* shm) {
int row = 10;
int column = 10;
char (*stream)[row][column]; //2D Dimensional array, fish can only move last row of 2d
//Initializing grid first
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
(*stream)[i][j] = '~';
}
}
printf("Fish: %d \n", shm[0]);
printf("Shm2 is: %d \n", shm[1] );
for (int k = 1; k < 20; k++) {
(*stream)[shm[k]/10][shm[k]%10] = 'O'; // pellets
}
(*stream)[shm[0]/10][shm[0]%10] = 'Y'; // Fish
for (int i = 0; i < row; i++) {
for (int j = 0; j < column; j++) {
printf("%c ", (*stream)[i][j]);
}
printf("\n");
}
}
void killProgram(pid_t fish, pid_t pellet, int *shm, int shmid) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
sleep(5);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
printf("Program finished! \n");
}
void handler(int num ) {
kill(fish,SIGUSR1);
kill(pellet, SIGUSR1);
shmdt(shm);
shmctl(shmid, IPC_RMID, NULL);
perror(" Interrupt signal is pressed!! \n");
exit(1);
}
Pellets.c
// Multiple pellets
//Process ID, position, eaten/misse
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include "include.h"
#define SHM_SIZE 1000
void handler(int);
void eatPellet();
void missPellet();
int main(int argc, char* argv[]) {
signal(SIGINT, handler);
attachSharedMemory();
srand(time(NULL));
int i = 1; // 1 - 19 are pellets
for (; i < 20; i++) {
int pelletPosition = rand() % 9 ; // random number from 0 - 9
if (shm[i] == -1){
// printf("hello %d \n", pelletPosition);
shm[i] = pelletPosition;
}
break;
}
while(1) {
printf("helloasd %d \n", shm[i]);
printf("i: %d \n", i);
if (shm[i] < 90) {
shm[i] += 10;
}
else if (shm[i] == shm[0]) {
eatPellet();
printf("Position: %d\n", shm[i] );
break;
// EATEN and KILL
}
else {
// KIll process, terminate
missPellet();
printf("Position: %d\n", shm[i] );
break;
}
// printf("%d\n",shm[i] );
i++;
sleep(1);
}
shmdt(shm);
return 0;
}
void handler(int num) {
shmdt(shm);
exit(1);
}
I looked at other stack overflow questions, and it seems that they problems because they didn't terminate with a NULL? I think the problem lies inside Pellets.c, but I can't seem to figure it out. Thanks.
Why this code give me different outputs every time?
Why it doesnt finish the loop?
What should I do to make it finish the loop? (despite context switches)?
Anything else I'm doing wrong?
Any help would be appreciated!
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define MAX 10
int buffer[MAX];
int fill = 0;
int use = 0;
int count = 0;
int loops = 15;
void put(int value) {
buffer[fill] = value;
fill = (fill + 1) % MAX;
count++;
printf("putting %d\n", value);
}
int get() {
int tmp = buffer[use];
use = (use + 1) % MAX;
count--;
return tmp;
}
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c_empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t c_fill = PTHREAD_COND_INITIALIZER;
void *producer(void *arg) {
printf("producer starts\n");
int i;
for (i = 0; i < loops; i++) {
pthread_mutex_lock(&mutex); // p1
while (count == MAX) // p2
pthread_cond_wait(&c_empty, &mutex); // p3
put(i); // p4
pthread_cond_signal(&c_fill); // p5
pthread_mutex_unlock(&mutex); // p6
}
return NULL;
}
void *consumer(void *arg) {
printf("consumer starts\n");
int i;
for (i = 0; i < loops; i++) {
pthread_mutex_lock(&mutex); // c1
while (count == 0) // c2
pthread_cond_wait(&c_fill, &mutex); // c3
int tmp = get(); // c4
pthread_cond_signal(&c_empty); // c5
pthread_mutex_unlock(&mutex); // c6
printf("consuming: %d\n", tmp);
}
return NULL;
}
int main(int argc, char *argv[]) {
printf("parent: begin\n");
pthread_t p, x;
pthread_create(&p, NULL, producer, NULL);
pthread_create(&x, NULL, consumer, NULL);
printf("parent: end\n");
return 0;
}
Makefile:
all: wcountb
wcountb: wcountb.c
gcc -g -Wall -o wcountb wcountb.c -lpthread
At the end of the main, you should call for pthread_join, like this:
...
pthread_join(p, NULL);
pthread_join(x, NULL);
return 0;
}
Without that call, the threads are created and when you reach the end of main(), then your program terminates, thus your threads may be able to finish their job, or not, which explains the fact that sometimes your code works.
The pthread_join() function shall suspend execution of the calling thread until the target thread terminates, unless the target thread has already terminated.
Taken from the manual of pthread_join().
An almost related question lies here.
Following scenario:
We are supposed to make x Threads maximum. Our main-function is supposed to make a single new thread with a pointer to the function 'makeThreads'. This function is supposed to make up to 2 threads, depending on how many threads are already there. Race conditions are to avoid.
I'm stuck. I'm not exactly sure how to solve the problem I'm running into, partly because I don't can't identify the problem itself.
Suggestions are greatly appreciated!
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#define MAX_THR 20
pthread_mutex_t mutex;
int threadCount = 0;
int randomNbr(){
int number = (rand() % 10) + 1;
return number;
}
void *makeThreads(void* number){
int rndnmb = *((int *) number);
pthread_mutex_lock(&mutex);
sleep(rndnmb);
pthread_t threadDummy;
int thread1, i, threadID, rndnbr;
threadID = threadCount;
printf("Hello from Thread %d!\n", threadID);
for(i = 0; i < 2; i++){
if(threadCount < MAX_THR){
rndnbr = randomNbr();
int *rnd = &rndnbr;
threadCount++;
thread1 = pthread_create(&threadDummy, NULL, *makeThreads, (void *) rnd);
pthread_join(threadDummy, NULL);
}
}
pthread_mutex_unlock(&mutex);
printf("Goodbye from Thread %d!\n", threadID);
}
int main(){
int t1, rndnbr;
pthread_t threadOne;
pthread_mutex_init(&mutex, NULL);
srand(time(NULL));
rndnbr = randomNbr();
int *rnd = &rndnbr;
threadCount++;
t1 = pthread_create(&threadOne, NULL, *makeThreads, (void *) rnd);
pthread_join(threadOne, NULL);
}