Assume the code below demonstrating a binary semaphore example.
In this example, we have a pthread that reads the source.txt and attempts to copy the content to destination.txt while locking it using a binary semaphore.
What happens in the comment section below without the semaphore?
#include <cstdlib>
#include <memory>
#include <filesystem>
#define _TIMESPEC_DEFINED
#include <pthread.h>
#include <semaphore.h>
#include <thread>
#include <valarray>
pthread_t StartFileAccessThread();
void *CopyFile(void *parameters);
int main(int argc, char* argv[])
{
pthread_t thread = StartFileAccessThread();
void *returnValue;
pthread_join(thread, &returnValue);
getchar();
return EXIT_SUCCESS;
}
pthread_t StartFileAccessThread()
{
std::string sourcePath("source.txt");
std::string destinationPath("dest.txt");
sem_t semaphore;
sem_init(&semaphore, 0, 0);
pthread_t thread;
void *parameters[3];
parameters[0] = &semaphore;
parameters[1] = &sourcePath;
parameters[2] = &destinationPath;
pthread_create(&thread, nullptr, &CopyFile, parameters);
// What happens without the binary semaphore?
sem_wait(&semaphore);
sem_destroy(&semaphore);
printf("Freeing ressources.\n");
return thread;
}
void *CopyFile(void *rawParameter)
{
void **parameters = static_cast<void **>(rawParameter);
sem_t *semaphore = static_cast<sem_t *>(parameters[0]);
std::string sourcePath(*static_cast<std::string *>(parameters[1]));
std::string destinationPath(*static_cast<std::string *>(parameters[2]));
sem_post(semaphore);
std::this_thread::sleep_for(std::chrono::seconds(2));
copy_file(sourcePath, destinationPath, std::experimental::filesystem::copy_options::overwrite_existing);
printf("File copied \n");
return nullptr;
}
What happens in the comment section below without the semaphore?
Without the semaphore, function startFileAccessThread() may return before the new thread finishes (or starts) copying its parameters from the argument object. That object is local to startFileAccessThread(), so its lifetime ends when that function returns. Undefined behavior results if the copy thread's accesses to it do not happen before that.
Related
I need to write a module that creates a file and outputs an inscription with a certain frequency. I implemented it. But when this module is running, at some point the system crashes and no longer turns on.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
#define BUF_LEN 255
#define TEXT "Hello from kernel mod\n"
int g_timer_interval = 10000;
static struct file *i_fp;
struct timer_list g_timer;
loff_t offset = 0;
char buff[BUF_LEN + 1] = TEXT;
void timer_rest(struct timer_list *timer)
{
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
i_fp = filp_open("/home/hajol/Test.txt", O_RDWR | O_CREAT, 0644);
kernel_write(i_fp, buff, strlen(buff), &offset);
filp_close(i_fp, NULL);
}
static int __init kernel_init(void)
{
timer_setup(&g_timer, timer_rest, 0);
mod_timer(&g_timer, jiffies + msecs_to_jiffies(g_timer_interval));
return 0;
}
static void __exit kernel_exit(void)
{
pr_info("Ending");
del_timer(&g_timer);
}
module_init(kernel_init);
module_exit(kernel_exit);
When the system crashes, you should get a very detailed error message from the kernel, letting you know where and why this happened (the "oops" message):
Read that error message
Read it again
Understand what it means (this often requires starting over from step 1 a couple of times :-) )
One thing that jumps out at me is that you're not going any error checking on the return value of filp_open. So you could very well be feeding a NULL pointer (or error pointer) into kernel_write.
Look at this Unix C program:
#include <stdio.h>
#include <signal.h>
void handler(int signum)
{
printf("Handler signum=%d\n",signum);
}
int main(int argc, char *argv)
{
printf("Start\n");
signal(SIGFPE, handler);
int i=10/0;
printf("Next\n");
return 0;
}
As you can see, i am connecting SIGFPE to an handler.
Then, i make a DIV0 erreur.
The handler is fired, that is great.
But, this handler is called in loop !
Why ?
Thanks
If you simply return from your handler, execution resumes at the point where the signal was thrown, which results in another divide by zero error, which results in the handler being called again, and so on. You need to arrange for execution to continue at some other point in the code. The traditional approach is to use setjmp/longjmp, something like this
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
jmp_buf buf;
void handler(int signum)
{
longjmp(buf, signum);
}
int main(int argc, char *argv)
{
int rc = setjmp(buf);
if (rc == 0) {
printf("Start\n");
signal(SIGFPE, handler);
int i=10/0;
}
printf("Handler signum=%d\n", rc);
printf("Next\n");
return 0;
}
Note: this approach is very old school, and probably someone can suggest a better way to handle it. Also, you are probably better off calling sigaction rather than signal, as the semantics of signal are not consistent across different versions of Unix.
I am running two processes (Process A and B) on the same core. Process B is multithreaded in which one thread is sending Signal to the next thread to wake it and start its work. At a time, only one thread of process B can run on the common core.
**//Process A**
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
int main(int argc, char const *argv[])
{
struct timeval tval_result;
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(2, &my_set);
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);
long int loopNum;
while(1)
{
gettimeofday(&tval_result, NULL);
printf("Dummy Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
//for(loopNum = 1; loopNum <= 100000; loopNum++);
//printf("Dummy!!! # \n");
}
return 0;
}
Following is the code of Process B.
//Import
#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#define NUM_THREADS 100
//global variables
pthread_cond_t condA[NUM_THREADS+1] = PTHREAD_COND_INITIALIZER;
pthread_cond_t condB = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_t tid[NUM_THREADS];
int state = 0;
void *threadA(void *data_)
{
int i = 0, rValue;
long int loopNum;
int turn = (intptr_t)data_;
struct timeval tval_result;
while(1)
{
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(2, &my_set);
sched_setaffinity(0, sizeof(cpu_set_t), &my_set);
/* Wait for state A */
pthread_mutex_lock(&mutex);
// while (state != STATE_A)
if(state != turn)
{
pthread_cond_wait(&condA[turn], &mutex);
}
pthread_mutex_unlock(&mutex);
//do stuff
gettimeofday(&tval_result, NULL);
printf("Time elapsed: %ld.%06ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
//for(loopNum = 1; loopNum <= 10000000000; loopNum++);
//printf("Hello Thread # %d\n", turn);
/* Set state TRUE for next thread */
pthread_mutex_lock(&mutex);
state = (state +1)%NUM_THREADS;
pthread_cond_signal(&condA[state]);
pthread_mutex_unlock(&mutex);
}
}
int main(int argc, char *argv[])
{
int data = 0;
int err;
while(data < NUM_THREADS)
{
//create our threads
err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
if(err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
else
printf("\n Thread created successfully\n");
data++;
}
pthread_exit(NULL);
}
I want to interleave the execution of process B in between threads of Process A for a very short duration (less than 1 microseconds). So, when thread i of process B finishes its work it'll send the signal to the next thread i+1 and in between, I want process A to come. This should be repeated for the rest of the course of execution.
When I am running above programs, process A is not able to come in between threads of the Process B. Is there any mechanism by which I can send signal with some timer so that signal does not reach the next thread immediately (and hence Process A comes for some time between two consecutive threads.)
There's no way you can force the Linux scheduler at that level.
You'll have to "signal" process A and then let it "signal" the other B thread.
But to "signal" may be a user space mechanism like spinning on a variable in shared memory.
I'd suggest you first try it with normal signals (going through the kernel) and see is the latency good enough. Only if it's too long, go play with spinning in user space.
Don't expect all that to work always under 1us. You'll probably get lots of jitter will have to move processes away from that core to reduce it, regardless of spinning or using kernel signalling.
For kernel signalling you may also use sockets, pipes, futexes,...
Now my question is, if you're running all that on one core, as you said, why not run it as a single thread - Just have one thread call B1, then A, then B2?
#include <pthread.h>
#ifndef __linux__
#include <windows.h>// to include the windows.h library//
#endif
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 5
#include <sys/timeb.h>
void *PrintHello(void *threadid)
{
srand(time(NULL));
long tid,a;
tid = (long)threadid;
a=rand()%5;
printf("Hello World! It's me, thread #%ld!%ld\n", tid,a);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t,a;
srand(time(NULL));
for(t=0; t<NUM_THREADS; t++){
a=rand()%5;
printf("In main: creating thread %ld,%ld\n", t,a);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
Alright I have this simple code and when I compile it inside the main() the random numbers
are different from one another but when i try to generate random numbers inside the threads, all the numbers that are produced are the same.
Try seeding from outside the threads. The problem is that you get the same seed for each thread
please help me, i want to implement timer using c in ubunto. i have the written the code but it is giving two errors. I am compiling it using -lrt option of gcc.
Errors i am getting is:
timer1.c: In function ‘main’:
timer1.c:18:52: error: ‘SIG’ undeclared (first use in this function)
timer1.c:18:52: note: each undeclared identifier is reported only once for each function it appears in
timer1.c:21:23: error: ‘handler’ undeclared (first use in this function)
My code is:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
timer_t timerid;
int main(int argc, char *argv[])
{
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
sigset_t mask;
struct sigaction sa;
printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
printf("timer ID is 0x%lx\n", (long) timerid);
// timer_create(CLOCKID, &sev, &timerid);
/* Start the timer */
its.it_value.tv_sec = 1000;
its.it_value.tv_nsec =0;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
timer_settime(timerid,0, &its, NULL);
sleep(10);
}
static void handler(int sig, siginfo_t *si, void *uc)
{
if(si->si_value.sival_ptr != &timerid)
{
printf("Stray signal\n");
}
else
{
printf("Caught signal from timer\n");
}
}
SIG is undeclared because you never declare it, and we can't tell you how to fix it since we don't know what it's supposed to be. handler is undeclared because you forgot the forward declaration. Put a copy of the function signature followed by a semicolon before the function where it's used.
static void handler(int sig, siginfo_t *si, void *uc);
int main(int argc, char *argv[])
{
...