how number of thread should be accepted via command line using pthread? - c

I am writting an application that has multiple threads in Linux environment using C or python. I am using pthread for that. But How number of threads should be accepted via command line.

In C you handle command line arguments by having main take two arguments,
int main(int argc, char** argv)
in which argc is the number of command line arguments (including the program itself) and argv is a pointer to a memory location where argc-1 pointers to strings with the actual arguments are located. Example:
int main(int argc, char** argv)
{
printf("The program was executed as %s.\n", argv[0]);
printf("The arguments were:\n");
for (int i = 1; i < argc; i++)
printf("%s\n", argv[i]);
return 0;
}
Let's now assume that your program takes a single command line argument, an integer telling you how many threads to spawn. The integer is given as a string, so we have to convert it using atoi:
if (argc != 2)
{
printf("Need exactly one argument!\n");
return 1;
}
int num_threads = atoi(argv[1]); // Convert first argument to integer.
if (num_threads < 1)
{
printf("I'll spawn no less than 1 thread!\n");
return 2;
}
Now what you do is simply create an array of thread handles,
pthread_t* threads = malloc(num_threads*sizeof(pthread_t));
and use it to store the thread handles as you start num_threads number of threads using pthread_create.
If you are not familiar with pthreads at all, I recommend this short tutorial.

If you were using a threading framework like OpenMP, then this is all handled automatically simply by setting the environment variable OMP_NUM_THREADS.
But if you're implementing threads "manually", you'll need to do it the way most runtime configuration is done: either by parsing argv[], or by setting an environment variable and using getenv().

Usually, you would just pass it like any other argument. I've used code similar to the following in projects before to specify fixed thread counts. This is fairly simple but suitable for situations where you don't need the full power of thread pooling (though you could just as easily set a minimum and maximum thread count the same way).
#include <stdio.h>
#define THRD_DFLT 5
#define THRD_MIN 2
#define THRD_MAX 20
static int numThreads = 0;
int main (int argCount, char *argVal[]) {
if (argCount > 1)
numThreads = atoi (argVal[1]);
if ((numThreads < 5) || (numThreads > THRD_MAX)) {
printf ("Number of threads outside range %d-%d, using %d\n",
THRD_MIN, THRD_MAX, THRD_DFLT);
numThreads = THRD_DFLT;
}
:
:

Related

make a program to run other program on C

I have a program that works like this
program1.exe program2.exe
I need to make it run like this
%USERPROFILE%\program1.exe program2.exe
How can that be done on C?
From what I could see, you're using Microsoft Windows.
There are (at least) two answers to your question, a simple one, and one tied to the Windows operating system interface, usually called Win32 API.
Let's use the simple one. If your prefer to have more control about the execution of the 2nd program, please comment.
#include <stdio.h> /* printf() */
#include <stdlib.h> /* system() */
int main(int argc, char* const* argv)
{
int rv;
if (argc < 2) {
printf("Please inform the name of the program to execute.\n");
return 1;
}
rv = system(argv[1]);
printf("Program execution returned %d\n", rv);
return 0;
}

Why return does not exit a process in xv6?

Here is my code for user/sleep.c:
#include "kernel/types.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
if (argc < 2)
{
printf("You have forgotten to pass an argument.");
exit(1);
}
int arg = atoi(argv[1]);
sleep(arg);
exit(0);
// return 0;
}
All is fine but with the return 0 instead of exit(0), I get the following error:
usertrap(): unexpected scause 0x000000000000000d pid=4
sepc=0x00000000000000f6 stval=0x0000000000003008
Why is that?
It's because xv6 is not standard on this point:  
see https://tnallen.people.clemson.edu/2019/03/04/intro-to-xv6.html
Returning after main is a special case that is not supported in XV6, so just remember to always exit() at the end of main instead of return. Otherwise, you will get a “trap 14,” which in this case is XV6-speak for “Segmentation Fault.” Finally, notice that our headers are different. There is no #include <stdio.h> as you might be used to. Again, this is because the standard library is different. Check out these headers to see what kind of user utilities you have available.
So why did we need exit() in xv6?
Because, when building a program with gcc for linux for instance, the tool chain add the required exit call: see https://en.wikipedia.org/wiki/Crt0
In short, on linux, your program don't start at main but at start:
void start(void) {
/* get argc, argv, env) */
int r = main(argc, argv, envp); /* << start calls the actual main */
exit(r);
}
On xv6, on contrary, the real starting point is main when OS try to return from main, it has no address to pop what cause a segfault

How to pass command line arguments to C program using execlp

I am trying to use execlp in a c program to run another c program. The exec function does call the program, but it does not pass the integer arguments correctly. My exec call is:
int exec_arg_1, exec_arg_2;
if(pid == 0){
printf("Repeat Number: %d, Process Number: %d\n", exec_arg_1, exec_arg_2);
execlp( "/home/drlight/Desktop/asp/Assignment_3/philosopher.o",
"philosopher.o", &exec_arg_1, &exec_arg_2, NULL );
printf("Exec didn't work...\n");
}
I assign values to the exec_arg ints, and print them right before to make sure they're correct, but the philosopher.o function just reads 0's from the location. If I run philosopher.o from the command line, it reads the arguments normally.
Arguments to programs are always strings.
int exec_arg_1, exec_arg_2;
if (pid == 0){
printf("Repeat Number: %d, Process Number: %d\n", exec_arg_1, exec_arg_2);
char arg1[20], arg2[20];
snprintf(arg1, sizeof(arg1), "%d", exec_arg_1);
snprintf(arg2, sizeof(arg2), "%d", exec_arg_2);
execlp( "/home/drlight/Desktop/asp/Assignment_3/philosopher.o",
"philosopher.o", arg_1, arg_2, NULL );
fprintf(stderr, "Exec didn't work...\n");
exit(1);
}
Note that execlp() is really only useful with a fixed number of arguments (or, a least, when there is a small fixed upper bound on the number of arguments). Most often, execvp() is a better choice.
This page includes plenty of usage examples....
EDIT : Added code snippet from the link
A code snippet from the link above
static void show_info_page(const char *git_cmd)
{
const char *page = cmd_to_page(git_cmd);
setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
execlp("info", "info", "gitman", page, (char *)NULL);
die(_("no info viewer handled the request"));
}
The best practice would be having a look at the execlp(3) man page in the first place I reckon.
EDIT : Added explanation of execlp(3) fro mthe man page
FreeBSD man page explains the usage of execlp() as follows
int
execlp(const char *file, const char *arg, ... /*, (char *)0 */);
The initial argument for these functions is the pathname of a file which
is to be executed.
The const char *arg and subsequent ellipses in the execl(), execlp(), and
execle() functions can be thought of as arg0, arg1, ..., argn. Together
they describe a list of one or more pointers to null-terminated strings
that represent the argument list available to the executed program. The
first argument, by convention, should point to the file name associated
with the file being executed. The list of arguments must be terminated
by a NULL pointer.
The functions execlp(), execvp(), and execvP() will duplicate the actions
of the shell in searching for an executable file if the specified file
name does not contain a slash ``/'' character. For execlp() and
execvp(), search path is the path specified in the environment by
``PATH'' variable. If this variable is not specified, the default path
is set according to the _PATH_DEFPATH definition in <paths.h>, which is
set to ``/usr/bin:/bin''
PS : some information, such as default search path, mat vary based on your system
Your issue is that execlp takes string pointers not integers for its arg parameters. From the manpage
int execlp(const char *file, const char *arg, ...);
You will have to convert these to strings before passing them to execlp.
#include<stdio.h>
#include<unistd.h>
#define MAXDIGITS 22
main()
{
int exec_arg_1, exec_arg_2;
char execStr1[MAXDIGITS + 1];
char execStr2[MAXDIGITS + 1];
exec_arg_1 = 750;
exec_arg_2 = 25;
snprintf(execStr1, MAXDIGITS + 1, "%d", exec_arg_1);
snprintf(execStr2, MAXDIGITS + 1, "%d", exec_arg_2);
printf("Our Strings: %s, %s\n", execStr1, execStr2);
execlp("/home/drlight/Desktop/asp/Assignment_3/philosopher.o", "philosopher.o", execStr1, execStr2, NULL);
}
You need to make sure MAXDIGITS is large enough to hold all the decimal digits of your number, but 25 should be sufficient for even longs on most current platforms. However keep in mind that in future versions of gcc and/or with different compilers this may be different. Don't forget to leave room for the negative either. You can check these maximums by importing limits.h and printing the values of INT_MAX and LONG_MAX.
#include<stdio.h>
#include<limits.h>
main(int argc, char * argv[])
{
printf("Int max: %d\n", INT_MAX);
printf("Long max: %ld\n", LONG_MAX);
}

Using an if/else statment to check that enum arguments exist

I'm having a slight issue with my current piece of code and trying to check that arguments have been passed to enum before trying to continue with the program;
enum arg {argName, sineArg, sampleArg, argC}eargs;
int main(int argc, char *argv[]){
long samplingRate = atol(argv[sampleArg]);
float sineFreq = atof(argv[sineArg]);
if (argC < eargs ){
printf("Usage: sineFreq\tsamplingRate\n");
}else{}
}
The code compiles fine, although when run without arguments the program returns "Segmentation fault: 11" instead of the usage message that I want to print to console.
you have to do the check before accessing argv[...]
EDIT: the check itself is wrong too (eargs is undefined; you should write
int main(int argc, char *argv[]) {
if (argc < argC) /* --> you should change you naming conventions! */
return EXIT_FAILURE;
long samplingRate = atol(argv[sampleArg]);
Your usage check is against eargs that has nothing to with the number of command line arguments passed. No matter how many arguments you pass, eargs is always going to be 0.
Also you should do the check before using any of the command line arguments. Place the condition at the start of main():
#include<stdio.h>
#include <stdlib.h>
enum arg {argName, sineArg, sampleArg, argC}eargs;
int main(int argc, char *argv[]) {
/* if ( argc < 3) would be explicit and clear here */
if (argc < argC ) { /* You expect at least two arguments */
printf("Usage: sineFreq\tsamplingRate\n");
return 1; // return from main on failure
}
long samplingRate = atol(argv[sampleArg]);
float sineFreq = atof(argv[sineArg]);
....
}
I have also included standard headers as you are using printf() and atol()
you need to change argC to argc, in the if statement...c is case-sensitive!!!
When you run the code without arguments, this
long samplingRate = atol(argv[sampleArg]);
accesses argv[2], which is undefined behavior, since you don't provide enough args (there are only argv[0] = program name and argv[1] = NULL indicating the end of the argv[]).

Explanation of a basic multithreading program in C using Pthread

I am trying to learn multithreading programming in C and trying to understand basic program. I could not understand the runner function and why is it returning a pointer to a type void and passing a parameter which is also a pointer to void. Also , I could not understand the parameters of main.
int sum; / this data is shared by the thread(s)
void *runner(void *param); / the thread
int main(int argc, char *argv[])
{
pthread_t tid; / the thread identifier /
pthread.attr_t attr; / set of thread attributes /
if (argc != 2) {
fprintf(stderr,"usage: a.out <integer value>\n");
return -1;
}
if (atoi(argv[1]) < 0) {
fprintf(stderr,"%d must be >= 0\n",atoi(argv[1]));
return -1;
/ get the default attributes /
pthread.attr.init (&attr) ;
/ create the thread /
pthread^create(&tid,&attr,runner,argv[1]);
/ wait for the thread to exit /
pthread_join (tid, NULL) ;
printf("sum = %d\n",sum);
/ The thread will begin control in this function /
void *runner(void *param)
{<br />
int i, upper = atoi(param);
sum = 0;<br />
for (i = 1; i <= upper; i
sum += i;
pthread_exit (0) ;
The parameters to main first. argc is the number of command-line parameters, including the program name. argv is an array of pointers to zero-delimited strings, which are the parameters themselves. So, if you run your program from the command-line like this:
myprog x y z
Then argc will be 4, argv will look like this:
argv[0]: "myprog"
argv[1]: "x"
argv[2]: "y"
argv[3]: "z"
argv[4]: ""
The final element should be an empty string. The exact format of the first element (program name) varies depending on the operating system and the exact way the program is called.
Your runner function is a type of function sometimes generally known as a callback. It is called by someone else (the pthread library). In order for someone else to call your function, it has to know it's return type and parameters, so these are fixed, even when they are not used.
So runner has to return a void * (untyped pointer) and take a void * parameter, even when it does not actually use either (it can return NULL). It is that way because that is what the pthread library expects.

Resources