Cat unix command multithread implementation - c

Hi im trying to implement faster cat than the one provided.
My current implementation looks like this:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define BUF_SIZE 1024*1024*1024
char buffer[BUF_SIZE];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_var2 = PTHREAD_COND_INITIALIZER;
int readed = 0;
/*
Read characters from standard input and saves them to buffer
*/
void *consumer(void *data) {
int r;
while(1) {
//---------CRITICAL CODE--------------
//------------REGION------------------
pthread_mutex_lock(&mutex);
if (readed > 0)
{
pthread_cond_wait(&cond_var2, &mutex);
}
r = read(0, buffer, BUF_SIZE);
readed = r;
pthread_cond_signal(&cond_var);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (r == -1){
printf("Error reading\n");
}
else if (r == 0) {
pthread_exit(NULL);
}
}
}
/*
Print chars readed by consumer from standard input to standard output
*/
void *out_producer(void *data) {
int w;
while(1){
//---------CRITICAL CODE--------------
//-------------REGION-----------------
pthread_mutex_lock(&mutex);
if (readed == 0)
{
pthread_cond_wait(&cond_var, &mutex);
}
w = write(1, buffer, readed);
readed = 0;
pthread_cond_signal(&cond_var2);
pthread_mutex_unlock(&mutex);
//------------------------------------
if (w == -1){
printf("Error writing\n");
}
else if (w == 0) {
pthread_exit(NULL);
}
}
}
What would you suggest to make it faster?
Any ideas?
I was thinking about the BUF_SIZE, what would you think would be optimal size of buffer?
Main just makes the threads:
int main() {
// Program RETURN value
int return_value = 0;
// in - INPUT thread
// out - OUTPUT thread
pthread_t in, out;
// Creating in thread - should read from standard input (0)
return_value = pthread_create(&in , NULL, consumer, NULL);
if (return_value != 0) {
printf("Error creating input thread exiting with code error: %d\n", return_value);
return return_value;
}
// Creating out thread - should write to standard output (1)
return_value = pthread_create(&out, NULL, out_producer, NULL);
if (return_value != 0) {
printf("Error creating output thread exiting with code error: %d\n", return_value);
return return_value;
}
return_value = pthread_join(in, NULL);
return_value = pthread_join(out, NULL);
return return_value;
}

How exactly is adding threads to cat going to make it faster? You can't just throw parallelism at any program and expect it to run faster.
Cat basically just transports every line of input (usually from a file) to output. Since it's important that the lines are in order, you have to use mutual exclusion to avoid racing.
The upper bound of the speed (the fastest that cat can run) in parallel cannot be higher than cat in serial, since every thread must perform the serial actions, along with the cost of synchronization.

Related

c program deals with multithreading

I need help with my c program, I have most of it done but it has some issues.
The program is about ** Exploring Synchronization Among Processes and Threads.**
You are given three (3) processes in one program that work together to solve a producer consumer problem:
2 processes are “producers” and each process produces its own type of product in a continuous loop. That is, one product type produced by one producer and a different product type by the other producer.
One Process is a “consumer” of products and consist of five (5) threads:
1 thread is a ‘distributor’ thread
two (2) threads consume one type of product (ex. consumes only product type 1)
two (2) threads consume a second type of product (ex. consumes only product type 2).
The consumer process contains two (2) product storage buffers, each comprised of a fixed number of slots. The number of slots in the buffers are to be different (one has more slots than
the other). You choose and specify the number of slots in each buffer as a definition in your
program solution
Communication between the producer processes and the consumer process is to be through a
single “pipe”. This single, shared pipe is used to communicate between each producer process
and the consumer process. Each producer process writes into this pipe the product to be
consumed by the consumer process.
Final program delivery: completion of the product consumer threads, output file design and
write functions; sample data runs with output files
I have most of it done but it has some issues.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <fcntl.h>
#include <pthread.h>
#define BUFFER_SIZE1 20
#define BUFFER_SIZE2 30
typedef struct
{
int count;
int productType;
} product;
int count = 0;
int fd[2];
pthread_mutex_t lock;
pthread_cond_t cond;
typedef struct
{
product *values;
int head;
int tail;
int numEntries;
int size;
} queue;
queue q1;
queue q2;
void producer(int args);
void *consumer(void *args);
void *distributor(void *args);
void initQ(queue *q, int size);
bool QEmpty(queue *q);
bool QFull(queue *q);
bool put(queue *q, product prod);
product get(queue *q);
// https://www.youtube.com/watch?v=l6zkaJFjUbM
// https://www.geeksforgeeks.org/multithreading-c-2/
int main(int argc, char const *argv[])
{
// Creating 5 threads 4 consumer and 1 distributor
pthread_t th[5];
// Creating our pipe, fd[0] is read end, fd[1] is write end
if (pipe(fd) == -1)
{
perror("error creating pipe");
exit(1);
}
// Initializing both buffers
initQ(&q1, BUFFER_SIZE1);
initQ(&q2, BUFFER_SIZE2);
int pid1;
int pid2;
int consId1 = 1;
int consId2 = 2;
// Initializing lock
pthread_mutex_init(&lock, NULL);
// Initialziing condition variables
pthread_cond_init(&cond, NULL);
// Create first producer process using fork(), child process 1
if (pid1 = fork() == 0)
{
producer(1);
}
// Create second prodcuer process using fork(), child process 2
else if (pid2 = fork() == 0)
{
producer(2);
}
// Create distrubtor and consumer threads, parent process
else
{
// Creating 4 threads using for loop and pthread_create
for (int i = 0; i < 4; i++)
{
// 2 consumer threads for product type 1
if (i == 1 || i == 2)
{
if (pthread_create(&th[i], NULL, &consumer, &consId1) != 0)
{
perror("Error creating thread");
}
}
// 2 consumer threads for product type 2
else
{
if (pthread_create(&th[i], NULL, &consumer, &consId2) != 0)
{
perror("Error creating thread");
}
}
}
// use pthread_join to wait for preivous thread to terminate
for (int i = 0; i < 4; i++)
{
if (pthread_join(th[i], NULL) != 0)
{
perror("Error joining thread");
}
}
// Distributor thread
close(fd[1]);
while (1)
{
product prod;
// Using lock and condition variable around crit section to avoid race condition
// pthread_mutex_lock(&lock);
// pthread_cond_wait(&cond, &lock);
// Read from the pipe
read(fd[0], &prod, sizeof(prod));
if (prod.productType == 1)
{
put(&q1, prod);
}
else
{
put(&q2, prod);
}
}
// pthread_cond_signal(&cond);
// pthread_mutex_unlock(&lock);
// Close read end of the pipe
close(fd[0]);
}
return 0;
}
// Creating the producers
void producer(int args)
{
int prodCount = 0;
product prod;
prod.productType = args;
// Close read end of the pipe
close(fd[0]);
while (1)
{
prodCount++;
prod.count = prodCount;
// Send product to the pipe so the consumer can use
write(fd[1], &prod, sizeof(prod));
// Sleep for 0.01 - 0.2 seconds after each loop
int time = (rand() % (200000 - 10000 + 1)) + 10000;
usleep(time);
}
// Close write end of the pipe
close(fd[1]);
}
void *consumer(void *args)
{
int consCount1;
int consCount2;
FILE *fp;
fp = fopen("output.txt", "w");
product prod;
int prodType = *(int *)args;
while (1)
{
if (prodType == 1)
{
get(&q1);
consCount1++;
fprintf("Thread ID: %d\n", prodType);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount1);
}
else
{
get(&q2);
consCount2++;
fputs("Thread ID: 2\n", fp);
fprintf(fp, "Product Type: %d\n", prod.productType);
fprintf(fp, "Production Sequence #: %d\n", prod.count);
fprintf(fp, "Consumption Sequence #: %d\n", consCount2);
}
}
fclose(fp);
}
// https://www.youtube.com/watch?v=oyX30WVuEos&t=196s
// Circular buffer
void initQ(queue *q, int size)
{
q->size = size;
q->values = malloc(sizeof(product) * q->size);
q->numEntries = 0;
q->head = NULL;
q->tail = NULL;
}
// Checks if the queue is empty
bool QEmpty(queue *q)
{
return (q->numEntries == 0);
}
// Checks if the queue is full
bool QFull(queue *q)
{
return (q->numEntries == q->size);
}
// Used for adding products to the queue
bool put(queue *q, product prod)
{
// If the queue is full we can not add to it
if (QFull(q))
{
return false;
}
// Add product to the end of the queue
q->values[q->tail] = prod;
q->numEntries++;
// Move index of the tail
q->tail = (q->tail + 1);
// If index goes out of bounds set back to 0
if (q->tail >= q->size)
{
q->tail = 0;
}
return true;
}
// Used for removing products for the queue
product get(queue *q)
{
product result;
// If the queue is empty we can not dequeue anymore
if (QEmpty(q))
{
perror("Error on dequeue");
}
// Remove from the head of the queue
result = q->values[q->head];
q->head = (q->head + 1) & q->size;
q->numEntries--;
return result;
}
I suggest to revise the code to make it more readable since now it's quite hard to understand.
Here I point out some issues of your code that lead to errors:
if condition if (pidN = fork() == 0) {...}
you should fork() first and then check the pid:
int pidN = fork();
if (pidN == 0) {...}
fprintf() function fprintf("Thread ID: %d\n", prodType);
either write the function fputs or fprintf:
fputs("Thread ID: \n", fp);
or
fprintf(fp, "Thread ID: %d\n", prod.productType);
Parameter of the fprintf() function: pay attention to the variable you're passing since prodType does not exist.

Only three of my five threads are executing, synchronizing using mutexes

I am doing an academic exercise for an OS class where we synchronize five detached threads using ONLY mutex locks and unlocks. We "CANNOT force the threads into any serial execution. Once spawned they must be free from external influences (other than the mutexes). The parent should NOT employ a pthread_join."
I am spawning 5 threads, detaching them and then using each threads to read in data and update a global variable. Currently my code spawns the 5 threads but only three of them output their ID's and none of them get into the while loop. Any help/advice here would be appreciated!
Output:
thread: 6156515168
thread: 6156515192
thread: 6156515176
There is a sleep in main which if uncommented provides the expected output, but this would be forcing a serial execution..
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <pthread.h>
pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER; // declaring mutex
int FileNameHelper=1;
int balance=0;
void* detatchedThread(void *param){
long tid = (long)param;
char* base = "data";
char filename[256];
char buf[100];
sprintf(filename, "%s%d.in", base, FileNameHelper); //creates data1.in, data2.in...
FileNameHelper ++;
FILE *inputFile = fopen(filename, "r");
printf ("thread: %ld\n", tid);
// critical sec line
if(fgets(buf, sizeof buf, inputFile) == NULL)
return NULL; // could not read first line
sleep(1); // make sure each thread runs long enough to get the random update behavior required.
pthread_mutex_lock(&mutex_lock); //we are in the critical section, lock mutex
while(fgets(buf, sizeof buf, inputFile) != NULL) {
int val;
if(sscanf(buf, "%d", &val) != 1){
break;
}
printf("%d\n", val);
balance += val;
printf ("Account balance after thread %ld is $%d\n", tid, balance);
}
pthread_mutex_unlock(&mutex_lock);
if(buf[0] != 'W')
return NULL;// last line data was invalid
pthread_exit(NULL);
}
int main(){
pthread_t th[5];
//initialize the mutex
if(pthread_mutex_init(&mutex_lock, NULL) != 0){
printf("\nmutex init has failed\n");
return 1;
}
//call the 5 threads, Detach the threads once they are created.
for (int i = 0; i < 5; i++){
pthread_create(&th[i], NULL, detatchedThread, (void *)&th[i]);
pthread_detach(th[i]);
//sleep(1); uncommenting this line gives me the expected behavior
}
pthread_mutex_destroy(&mutex_lock);
return 0;
}

Initialise semaphores using sem_open

In my producer and consumer problem, I use sem_open() to initialize the semaphores. How could I test if sem_open() works in a correct way?
The program can be compiled, but when I run the program it does not print anything. I test the program and found the problem maybe about sem_open(). I find if I comment the sem_open() in the program, the program will run correctly.
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
pthread_t pro_thread, con_thread;
pthread_mutex_t mutex;
int counter = 0;
sem_t *empty, *full;
void print_buffer(int counter) {
for (int i = 0; i < counter; i ++)
{
printf("*");
}
printf("\n");
}
void* producer(void* var) {
int item;
while(1) {
item = rand() % 100 + 1;
sem_wait(empty);
pthread_mutex_lock(&mutex);
while (counter == BUFFER_SIZE)
; // waiting
if(counter < BUFFER_SIZE) {
buffer[counter] = item;
counter ++;
printf("Producer: ");
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(full);
}
}
void* consumer(void* var) {
int item;
while(1) {
sem_wait(full);
pthread_mutex_lock(&mutex);
while (counter == 0)
; // waiting
if(counter > 0) {
counter --;
print_buffer(counter);
}
sleep(1);
pthread_mutex_unlock(&mutex);
sem_post(empty);
}
}
int main(int argc, char *argv[]) {
pthread_mutex_init(&mutex, NULL);
empty = sem_open("/mysem", O_CREAT, 0644, BUFFER_SIZE);
full = sem_open("/mysem", O_CREAT, 0644, 0);
pthread_create(&pro_thread, NULL, producer, NULL);
pthread_create(&con_thread, NULL, consumer, NULL);
pthread_exit(NULL);
return 0;
}
As stated in the sem_open man page:
The semaphore is identified by name.
Since your code provides the same name value (/mysem) for both sem_open calls it results in referencing the same semaphore for both full and empty. That's clearly not what the logic of the program should be. Instead, open different semaphores for each. It's also best practice to check the return values of all function calls.
empty = sem_open("/empty_sem", O_CREAT, 0644, BUFFER_SIZE);
if (empty == SEM_FAILED) {
perror("Failed to open semphore for empty");
exit(-1);
}
full = sem_open("/full_sem", O_CREAT, 0644, 0);
if (full == SEM_FAILED) {
sem_close(empty);
perror("Failed to open semphore for full");
exit(-1);
}

parallel running of threads unreliable behaviour

I've wrote the following program. I expect that this function print 1, 2 sequentially but
the program waits some time(for example 10 sec) and then prints all of the result.
here is the code:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
void *thread_function(void *arg);
char message[] = "Hello World";
int run_now = 1;
int main()
{
int res;
pthread_t a_thread;
void *thread_result;
res = pthread_create(&a_thread, NULL, thread_function, (void *)message);
if (res != 0)
{
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
int print_count1 = 0;
while(print_count1++ < 20)
{
if (run_now == 1)
{
printf("1");
run_now = 2;
}
else
{
sleep(1);
}
}
printf("\nWaiting for thread to finish...\n");
res = pthread_join(a_thread, &thread_result);
if (res != 0)
{
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined. \n");
exit(EXIT_SUCCESS);
}
void *thread_function(void *arg)
{
int print_count2 = 0;
while(print_count2++ < 20)
{
if (run_now == 2)
{
printf("2");
run_now = 1;
}
else
{
sleep(1);
}
}
}
i expect to 1, 2 be printed every 1 seconds, but program is waiting some times and then prints all of the string entirely. can anybody tell me what's the reason?
int run_now is accessed concurrently and therefore its access needs to be protected.
To do so use a mutex for example:
...
int run_now = 1;
pthtread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int main()
{
...
while(print_count1++ < 20)
{
pthread_mutex_lock(&mutex);
int run_now_equals_1 = (run_now == 1);
if (run_now_equals_1)
{
printf("1");
run_now = 2;
}
pthread_mutex_unlock(&mutex);
if (!run_now_equals_1)
{
sleep(1);
}
}
...
}
void *thread_function(void *arg)
{
int print_count2 = 0;
while(print_count2++ < 20)
{
pthread_mutex_lock(&mutex);
int run_now_equals_2 = (run_now == 2);
if (run_now_equals_2)
{
printf("2");
run_now = 1;
}
pthread_mutex_unlock(&mutex);
if (!run_now_equals_2)
{
sleep(1);
}
}
}
Well, there are a few problems with your program. First, printf may buffer things internally, so you won't see them. This is probably what you refer to. You need to fflush stdout after each printf. The more serious problem is that your program is wrong, as it uses a non-atomic, non-volatile variable for communication.
In your thread_function, the compiler is free to move the load of run_now out of the loop and only work with a register copy, hence the loop won't ever notice that another thread changed the value in memory. You should always use atomic intrinsics to access shared variables like this.
Use fprintf(stderr,"...") instead of printf, or add a fflush(stdout) after each printf.
This is because stout is flushed only when OS decides to flush it, while stderr is flushed as soon as fprintf is called.

Reading File and enforcing order of operation between processes

I am attempting to follow a tutorial which asks me to edit example code to get a program to run two processes which take turns to output the lyrics to a song ('There's a hole in the bucket').
My problem is that the file gets outputted as a whole and not alternativley like it should see screen shot for what i am talking about : http://imgur.com/NusvhVA
My code is below. Thanks.
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>
#define KEY 87654 //Unique semaphore key
int main()
{
int id; /* Number by which the semaphore is known within a program */
FILE *file;
file = fopen("207song.txt", "r" );
int c;
union semun {
int val;
struct semid_ds *buf;
ushort * array;
} argument;
argument.val = 1;
/* Create the semaphore with external key KEY if it doesn't already
exists. Give permissions to the world. */
id = semget(KEY, 1, 0666 | IPC_CREAT);
/* Always check system returns. */
if(id < 0) {
fprintf(stderr, "Unable to obtain semaphore.\n");
exit(0);
}
/* What we actually get is an array of semaphores. The second
argument to semget() was the array dimension - in our case
1. */
/* Set the value of the number 0 semaphore in semaphore array
# id to the value 0. */
if( semctl(id, 0, SETVAL, argument) < 0) {
fprintf( stderr, "Cannot set semaphore value.\n");
} else {
fprintf(stderr, "Semaphore %d initialized.\n", KEY);
}
int pid=fork();
const int HENRY_DONE = 0;
const int LIZA_DONE = 1;
volatile int flag = HENRY_DONE;
if(pid) {
struct sembuf operations[1];
int retval; /* Return value from semop() */
/* Get the index for the semaphore with external name KEY. */
id = semget(KEY, 1, 0666);
if(id < 0){
/* Semaphore does not exist. */
fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
exit(0);
}
operations[0].sem_num = 0;
/* Which operation? Subtract 1 from semaphore value : */
operations[0].sem_op = -1;
/* Set the flag so we will wait : */
operations[0].sem_flg = 0;
while(1){
//Process 1
//wait
operations[0].sem_op = -1;
retval = semop(id, operations, 1);
//critical section
printf("Liza's Part: \n");
fflush(stdout);
sleep(1);
while ((c = getc(file)) !=EOF)
if (c == "\n") {
putchar(c);
break;
}
else
putchar(c);
fflush(stdout);
operations[0].sem_op = 1;
//signal
retval = semop(id, operations, 1);
}
}else{
//Process 2
struct sembuf operations[1];
int retval; /* Return value from semop() */
/* Get the index for the semaphore with external name KEY. */
id = semget(KEY, 1, 0666);
if(id < 0){
/* Semaphore does not exist. */
fprintf(stderr, "Program sema cannot find semaphore, exiting.\n");
exit(0);
}
operations[0].sem_num = 0;
/* Which operation? Subtract 1 from semaphore value : */
operations[0].sem_op = -1;
/* Set the flag so we will wait : */
operations[0].sem_flg = 0;
while(1){
//wait
operations[0].sem_op = -1;
retval = semop(id, operations, 1);
//critical section
printf("Henry's Part: \n");
fflush(stdout);
sleep(1);
while ((c = getc(file)) !=EOF)
if (c == "\n") {
putchar(c);
break;
}
else
putchar(c);
fflush(stdout);
//signal
operations[0].sem_op = 1;
retval = semop(id, operations, 1);
}
}
}
If your while loop you have:
while ((c = getc(file)) !=EOF)
if (c == "\n") {
getc returns an integer, "\n" is a c-string of type char*. That
comparison will not match, leading the first comsumer to show the whole file.
You probably want
c == '\n'
note the single quotes 'rather than double " The single quote will be a char, which will compare reasonably with an int.

Resources