I just started programming in multiple threading and tinkering with some templates around, I produced this possibly horrible code:
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
typedef struct __myarg_t //argument struct?
{
int a;
char *b;
} myarg_t;
typedef struct __myret_t //return thread struct?
{
int x;
char *y;
} myret_t;
char cat[100] = ""; //used for concatenation of argv
void *mythread(void *arg)
{
myarg_t *m = (myarg_t *)arg;
int print_index = 0;
printf("THREAD ID: %lu\n", pthread_self());
for (print_index = 0; print_index < m->a; print_index++)
{
printf("Printing %d th character %c\n", print_index, *(m->b + print_index));//spelling the words
}
myret_t *rfin = malloc(sizeof(myret_t));
rfin->x = 1;
strcat(cat, m->b);//concatenating argv with
strcat(cat, " "); //a space to cat
rfin->y = cat;//reassigning the new sentence to rfin
return (void *)rfin;
}
int main(int argc, char *argv[])
{
if (argc == 1)
{
printf("Enter a word as argument before commandline.\nExiting...\n");
exit(0);
}
int rc = 0;
pthread_t p[argc - 1]; //total threads
myret_t *m; //return thread
myarg_t args; //argument thread?
int i = 1;
while (i < argc) //creating threads:
{
printf("THREAD:\t%d\n", i);
args.a = strlen(argv[i]);
args.b = (char *)malloc(strlen(argv[i]));
strcpy(args.b, argv[i]);
pthread_create(&p[i - 1], NULL, mythread, &args);
i++;
}
i = 1;
while (i < argc) // Wait for threads to complete
{
pthread_join(p[i - 1], (void **)&m);
i++;
}
printf("returned %d %s\n", m->x, m->y); //end concatenation result for myret_t *m;
return 0;
}
so when I execute it:
gcc -g task2.c -o thread -Wall -pthread
./thread hello there
It gives me the following as the result:
THREAD: 1
THREAD: 2
THREAD ID: 139848453601024
Printing 0 th character t
Printing 1 th character h
Printing 2 th character e
Printing 3 th character r
Printing 4 th character e
THREAD ID: 139848445208320
Printing 0 th character t
Printing 1 th character h
Printing 2 th character e
Printing 3 th character r
Printing 4 th character e
returned 1 there there
Instead of hello there. Is there some problem with the way I am concatenating? Should I be using another thread to do it?
Should I lock the concatenation part of the code because different threads are using it at the same time?
Any idea as to where I am going wrong? Any help/advice/criticism is more than welcome.
You have a race condition in your code -- you pass a pointer to args to the first thread, and then the main() function immediately overwrites the member-variables in the object that the pointer points to, while the first thread is running in parallel, so the first thread (usually) doesn't get a chance to see the original args.a or args.b values before they got overwritten. To avoid this, you could allocate a separate args struct for each thread, instead:
myarg_t * args = (myarg_t *) malloc(sizeof(myarg_t));
args->a = strlen(argv[i]);
args->b = (char *)malloc(strlen(argv[i])+1); // +1 for NUL terminator byte
strcpy(args->b, argv[i]);
pthread_create(&p[i - 1], NULL, mythread, args);
Related
I have written a program with a function that prints a character received as an argument continuously, and made 2 threads running that function. The program runs as intended and keeps printing 2 characters interlaced indefinitely. Here is the code:
#include <pthread.h>
#include <stdio.h>
void* print_char(void* th_param) {
char* ch = (char*)th_param;
while(1)
printf("%c", *ch);
return NULL;
}
int main() {
char* c1 = "a";
char* c2 = "b";
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)c1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)c2);
return 0;
}
Now I have to modify this program so the print function takes a number argument as well, and prints the character that number of times. What I try is this:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
}
return NULL;
}
int main() {
struct Params* p1 = (struct Params*)malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = (struct Params*)malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)p2);
while(1) {}
return 0;
}
But to no avail. Doesn't print a single character, the cursor just stands there blinking doing nothing. I have tried tampering with the code for hours and nothing has worked.
Note that there's not a problem with the struct, because the program works if I remove the for loop and put while(1) instead, and prints the character given to par->ch infinite times again.
The problem is buffered I/O.
Your main()-function loops infinitely, so the process doesn't terminate properly (only by being killed via an external signal), so the stdout-buffer is never flushed by regular process termination.
Since stdout is line-buffered by default, and your printf()s don't contain any newlines, and the amount of characters you try to print is smaller than the I/O-buffer, your program never writes out the buffer, so nothing is printed.
One approach would be to add fflush(stdout); after the printf()s in your thread function, or include a '\n' in the output.
Another (more sane) approach would be to have main() actually wait for the threads to finish, and gracefully terminate when they are done:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
//fflush(stdout);
}
return NULL;
}
int main() {
struct Params* p1 = (struct Params*)malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = (struct Params*)malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, (void*)p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, (void*)p2);
//while(1) {}
pthread_join(th_id, NULL);
pthread_join(th_id2, NULL);
free(p1); //make LeakSanitizer happy, don't leak memory
free(p2);
puts(""); //one newline for command-line beautification
fflush(stdout); //redundant after the puts(""), unless stdout is redirected to a non-interactive stream
return 0;
}
Thanks everyone, using fflush did the job.
To answer the person who asked what platform I ran this on, I was running this on Linux terminal. This was the homework for my OS lab class and pthread_create is all they have taught us so far, pthread_join and more thread management stuff come in later sessions.
Because of your while loop, stdout never get's flushed
Try this :
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
struct Params {
char* ch;
int num;
};
void* print_char(void* th_param) {
int i;
struct Params* par = (struct Params*)th_param;
for(i=0; i<par->num; i++) {
printf("%s", par->ch);
}
return NULL;
}
int main() {
struct Params* p1 = malloc(sizeof(struct Params));
p1->ch = "a"; p1->num = 5;
struct Params* p2 = malloc(sizeof(struct Params));
p2->ch = "b"; p2->num = 10;
pthread_t th_id;
pthread_create(&th_id, NULL, &print_char, p1);
pthread_t th_id2;
pthread_create(&th_id2, NULL, &print_char, p2);
fflush(stdout);
while(1) {;}
return 0;
}
I'm building a simple shell for a class. There are two programs in my shell directory, called "alomundo" and "echo". "./alomundo" prints "Alo mundo!" to console, and ./echo executes the ubuntu echo with given args.
The thing is my program only works if I declare the char aux[15]. Notice I don't use it aux for nothing. Can anyone understand whats wrong?
An example input would be
./shell echo a b, alomundo, echo abc
The correct output is
a b
Alo mundo!
abc
The output when char aux[15] is not declared is just:
Alo mundo!
abc
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char aux[15]; // <---- GRRRR
int child; // will hold the childs PID after fork()
int i = 0; // counter to loop through this mains *argv[]
int t = 0; // auxiliar counter to loops
int arg_len; // will hold the length of each argument while the argument is being processed
int args = 0; // current number of arguments in the argv1 vector
int send = 0; // boolean to check if the command should be executed in the current loop or not
char *command; // string to hold the main command name
char *argv1[15]; // vector to hold the arguments passed to execve
for(i=1; i<argc; i++) {
arg_len = strlen(argv[i]);
argv1[args] = (char *) malloc(sizeof(char) * 25);
for(t=0; t<25; t++) {
argv1[args][t] = '\0';
}
if (argv[i][arg_len-1] == ',') {
argv[i][arg_len-1] = '\0';
send = 1;
}
else if (i == (argc-1)) {
send = 1;
}
if (args == 0) {
command = (char *) malloc(sizeof(char) * 255);
strcpy(command, "./");
strcpy(argv1[args], "./");
strcat(command, argv[i]);
}
strcat(argv1[args], argv[i]);
args++;
if (send) {
child = fork();
if (child == 0) {
argv1[args+1] = 0;
execve(command, &argv1[0], envp);
return 0;
}
else {
waitpid(child);
free(command);
for (t=0; t<args; t++) {
free(argv1[t]);
argv1[t] = NULL;
}
args = 0;
send = 0;
}
}
}
return 0;
}
waitpid(child) seems wrong. Try:
// ...
#include <sys/wait.h>
// ...
pid_t child;
int wstatus;
// ...
else {
wait(&wstatus);
envp is not declared. Try:
// ...
int main(int argc, char *argv[], char *envp[]) {
// ...
Off-by-one error in argv1 processing. Try:
// ...
if (child == 0) {
argv1[args] = 0;
execve(command, argv1, envp); // why use &argv1[0] ?
// ...
I think (3) is the culprit.
Compiling with different levels of optimisation (-O, etc) seems to affect whether or not the erroneous +1 causes a problem.
I'm writing code for the Dining Philosopher thread problem for N number of philosophers from user input. I get an error for dereferencing void * pointer. What am I doing wrong specifically with passing in the array?
void *philosopher(void *arg_l);
int main()
{
int i,A,B;
scanf("%10d", &A);
scanf("%10d", &B);
printf("You got %d phils and %d turns each\n",A,B);
int args[2];
args[0] = A;
args[1] = B;
pthread_t thread_id[A];
sem_init(&mutex,0,1);
for(i=0;i<A;i++)
sem_init(&S[i],0,0);
for(i=0;i<A;i++)
{
args[2] = phil_num[i];
pthread_create(&thread_id[i],NULL,philosopher,&args);
printf("Philosopher %d is thinking\n",i+1);
}
for(i=0;i<A;i++)
pthread_join(thread_id[i],NULL);
}
void *philosopher(void *arg_l)
{
arg_l[0] = int A;
arg_l[1] = int B;
...
return NULL;
}
Since arg_l has type void *, you can't use the subscript operator [] on it. That would mean each element has type void, which cannot be instantiated. Also, the syntax on the right side of the assignment is not valid.
You need to cast the thread argument to int * before you can use it. Also, you need to pass in args without taking its address, since an array decays into a pointer to the first element when passed to a function.
pthread_create(&thread_id[i],NULL,philospher,args);
...
void *philospher(void *arg_l)
{
int *args = arg_l;
...
}
Your lines like:
arg_l[0] = int A;
are completely broken. You would get away with:
int A = ((int *)arg_l)[0];
You cannot dereference a void * validly, nor can you index them (in part because that requires dereferencing, in part because in standard C — as opposed to GNU C — the sizeof(void) is undefined). You need to convert to an appropriate type with a cast and then derefence, as shown.
Note: args[2] = phil_num[i]; is writing out of bounds (you define int args[2]; but it appears you need int args[3];.
You have to pass each philosopher a separate array because there is no guarantee that a given thread will have read the information before the main thread reassigns a new value. Usually, you'll use a structure, not an array, for the data passed to an individual thread; you have an initialized array of those structures so that each thread gets its own unique control information.
Is there any way you can give an example of this?
Somewhat like this. The key point is the array of struct Info, each of which is separately initialized (using a C99 compound literal) and a different element of the array is passed to each thread so that it gets its own data, rather than trying to share data with other threads.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
struct Info
{
int number;
int turns;
int diner;
};
enum { MAX_PHILOSOPHERS = 10 };
enum { MAX_TURNS = 99 };
static sem_t mutex;
static sem_t S[MAX_PHILOSOPHERS];
static void *philosopher(void *arg_l);
int main(void)
{
int A, B;
printf("How many philosophers? How many turns? ");
fflush(stdout);
if (scanf("%d %d", &A, &B) != 2)
{
fprintf(stderr, "Failed to read input\n");
return 1;
}
if (A < 2)
fprintf(stderr, "You specified too few philosophers (%d)\n", A);
if (A > MAX_PHILOSOPHERS)
fprintf(stderr, "You specified too many philosophers (%d, but the maximum is %d)\n",
A, MAX_PHILOSOPHERS);
if (B < 1)
fprintf(stderr, "You specified too few turns (%d)\n", B);
if (B > MAX_TURNS)
fprintf(stderr, "You specified too many turns (%d, but the maximum is %d)\n",
B, MAX_TURNS);
if (A < 2 || A > MAX_PHILOSOPHERS || B < 1 || B > MAX_TURNS)
return 1;
printf("You have %d philosophers who get %d turns each\n", A, B);
/* This assignment could be in the thread creation loop before pthread_create() */
/* Or in the loop that uses sem_init() */
struct Info info[A];
for (int i = 0; i < A; i++)
info[i] = (struct Info){ A, B, i};
sem_init(&mutex, 0, 1);
for (int i = 0; i < A; i++)
sem_init(&S[i], 0, 0);
pthread_t thread_id[A];
for (int i = 0; i < A; i++)
{
pthread_create(&thread_id[i], NULL, philosopher, &info[i]);
printf("Philosopher %d is thinking\n", i + 1);
}
for (int i = 0; i < A; i++)
pthread_join(thread_id[i], NULL);
printf("Dinner is over\n");
return 0;
}
static void *philosopher(void *arg_l)
{
struct Info *info = arg_l;
printf("N = %d, T = %d, I = %d\n", info->number, info->turns, info->diner);
/* ...do dining stuff; remember to share nicely!... */
return 0;
}
The #pragma allows the code to compile on macOS Sierra, which doesn't have working versions of the <semaphore.h> functions — they just return an error indication and set errno to ENOSYS (function not implemented).
This code should check the return value of the pthread functions and the semaphore operations too — it is being lazy not to do so.
Hi I am having trouble passing an integer argument to a thread and calculation the factorial using that integer. Here is my code.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <ctype.h>
void * factorial(void * number) {
int factorial = 1;
int counter = 1;
int newnum = *((int*)number);
printf("%d", newnum);
pthread_exit(NULL);
}
void * sumup( void * number) {
}
int main(int argc, char *argv[]) {
if(argc != 2) {
printf("Argument number error\n");
exit(1);
}
pthread_t thread1;
pthread_t thread2;
int i;
for(i = 0; i < argc; i++){
printf(argv[i]);
printf("\n");
}
int rc;
void * t = argv[1];
rc = pthread_create(&thread1, NULL, factorial, (void*)t );
if (rc != 0) {
printf("There was an error creating the thread\n");
exit(1);
}
pthread_exit(NULL);
exit(0);
}
Right now i am just trying to print the integer sent to get it working properly but here is my output:
./Task1
5
1162608693
It should printing out 5 instead of 1162608693
argv table stores pointers to characters. By doing:
void * t = argv[1];
int newnum = *((int*) t );
what you are trying to print is integer value of string "5". You are passing address of string:
'5' '\0'
casted to pointer to int, therefore you try to read integer value of first sizeof(int) bytes which yields:
5 0 [and you read sizeof(int)-2 bytes out of range]
which results in undefined behavior.
SOLUTION
To convert to integer a string passed as argument to your program use atoi or strtol which does better error checking.
Needed some assistance in solving a problem of "passing an element from a array of strings to a thread". My code is after this text. I declared an array of strings in the main function and then passed one element of the array to a thread. In the thread I typecast it back to char* type and then print, but it prints garbage values. Would be grateful for the solution:
#include <stdio.h>
#include <pthread.h>
void *agent(void *);
int main(int argc, char *argv[]) {
int i;
pthread_t agent_t[3];
char *agent_colour[3] = {"Red","White","Brown"};
for(i = 0 ; i <= 2 ; i++) {
pthread_create(&agent_t[i], 0, agent, &agent_colour[i]);
}
for(i = 0 ; i <= 2 ; i++) {
pthread_join(agent_t[i], NULL);
}
return 0;
}
void *agent(void *arg) {
char *colour = (char*)arg;
int x;
srand(time(NULL));
x = rand() % 5 + 1;
sleep(x);
printf("\n My name is Agent %s\n", colour);
pthread_exit(NULL);
}
My output is:
My name is Agent � #
My name is Agent � #
My name is Agent � #
Try this:
pthread_create(&agent_t[i], 0, agent, agent_colour[i]);
This is wrong in the pthread_create call
&agent_colour[i]
you just want to pass the string
agent_colour[i]
agent_colour is an array of pointer. So just pass like this agent_colour[i] in pthread create.