the following sample code shares the global variable "unit" between two threads. The struct is not marked volatile and I also don't use any memory barriers / mutex when accessing it's members.
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#include <semaphore.h>
struct unit
{
int data;
bool initialized:1;
};
static struct unit unit;
static sem_t semaphore;
void *thread1(void *arg)
{
(void)arg;
if (!unit.initialized)
{
unit.data = 5;
unit.initialized = true;
}
return NULL;
}
void *thread2(void *arg)
{
(void)arg;
struct timespec ts = { .tv_sec = 1 };
while (!unit.initialized)
{
(void)clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
}
unit.data = unit.data * 2;
return NULL;
}
static void signal_handler(int signal)
{
(void)signal;
(void)sem_post(&semaphore);
}
int main(void)
{
pthread_t t1;
pthread_t t2;
struct sigaction sa = { 0 };
sigemptyset(&sa.sa_mask);
sa.sa_handler = signal_handler;
(void)sigaction(SIGINT, &sa, NULL);
(void)sigaction(SIGTERM, &sa, NULL);
(void)sem_init(&semaphore, 0, 0);
(void)pthread_create(&t2, NULL, thread2, NULL);
(void)pthread_create(&t1, NULL, thread1, NULL);
(void)sem_wait(&semaphore);
printf("unit.data = %d\n", unit.data);
(void)pthread_join(t1, NULL);
(void)pthread_join(t2, NULL);
(void)sem_destroy(&semaphore);
return 0;
}
I compiled the code with and without optimization. It worked as intended in both situations, printing unit.data = 10 on the terminal.
gcc -Wall -Wextra main.c -lrt -o prog
//and
gcc -O3 -Wall -Wextra main.c -lrt -o prog
Is it guaranteed that the compiler won't optimize the code in thread2 to something like while(!unit.initialized) to while(!0) or unit.data = unit.data * 2; to unit.data = 0 * 2; because I don't use mutex / volatile? I ask because in code like below, I encountered that the loop will run forever if I use optimizations and don't specify the stop variable with volatile.
#include <signal.h>
static sig_atomic_t stop;
void signal_handler(int signal)
{
stop = 1;
}
int main(void)
{
//setup signal handler
while (!stop)
{
//do something
}
return 0;
}
So is data shared between threads at runtime always updated in the end? I am aware that not using mutexes will probably cause race conditions.
Related
I am trying to understand the behavior of volatile and compiler optimization in C through an example.
For this, I referred:
Where to use volatile?
Why is volatile needed in C?
https://software.intel.com/en-us/blogs/2007/11/30/volatile-almost-useless-for-multi-threaded-programming
All of the above posts have at least one answer related to signal handler so for this, I have written a simple code to actually implement and observe the behavior in Linux just for understanding.
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
int counter = 0;
void *thread0_func(void *arg)
{
printf("Thread 0\n");
while(1)
{
}
return NULL;
}
void *thread1_func(void *arg)
{
printf("Thread 1\n");
while(counter == 0)
{
printf("Counter: %d\n", counter);
usleep(90000);
}
return NULL;
}
void action_handler(int sig_no)
{
printf("SigINT Generated: %d\n",counter);
counter += 1;
}
int main(int argc, char **argv)
{
pthread_t thread_id[2];
struct sigaction sa;
sa.sa_handler = action_handler;
if(sigaction(SIGINT, &sa, NULL))
perror("Cannot Install Sig handler");
if(pthread_create(&thread_id[0], NULL, thread0_func, NULL))
{
perror("Error Creating Thread 0");
}
if(pthread_create(&thread_id[1], NULL, thread1_func, NULL))
{
perror("Error Creating Thread 0");
}
else
{
}
while(1)
{
if(counter >= 5)
{
printf("Value of Counter is more than five\n");
}
usleep(90000);
}
return (0);
}
This code is just for learning and understanding.
I tried compiling the code using:
gcc -O3 main.c -o main -pthread
But the compiler is not acting on global variable counter and is not optimizing it.
I was expecting *thread1_func to execute in a forever loop and the if (counter >= 5) to be never true.
What am I missing here?
GCC Version: gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4)
Your if tests on the value of counter are interspersed with calls to usleep and printf. These are opaque library calls. The compiler cannot see through them and so it has to assume they may have access to the counter external variable, and so it has to reload the counter variable after those calls.
If you move these calls out, the code gets optimized as you expect:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
int counter = 0;
void *thread0_func(void *arg)
{
printf("Thread 0\n");
while(1)
{
}
return NULL;
}
void *thread1_func(void *arg)
{
printf("Thread 1\n");
unsigned i=0;
while(counter == 0)
{
i++;
}
printf("Thread 1: %d, i=%u\n", counter, i);
return NULL;
}
void action_handler(int sig_no)
{
printf("SigINT Generated: %d\n",counter);
counter += 1;
}
int main(int argc, char **argv)
{
pthread_t thread_id[2];
struct sigaction sa;
sa.sa_handler = action_handler;
if(sigaction(SIGINT, &sa, NULL))
perror("Cannot Install Sig handler");
if(pthread_create(&thread_id[0], NULL, thread0_func, NULL))
{
perror("Error Creating Thread 0");
}
if(pthread_create(&thread_id[1], NULL, thread1_func, NULL))
{
perror("Error Creating Thread 0");
}
else
{
}
while(1)
{
if(counter >= 5)
{
printf("Value of Counter is more than five\n");
}
usleep(90000);
}
return (0);
}
Even if you make the counter variable static, the compiler will still not optimize, because although an external library definitely won't see the counter variable, the external call may theoretically have a mutex lock, which would allow another thread to change the variable without a data race. Now neither usleep nor printf are wrappers around a mutex lock, but the compiler doesn't know, nor does it do inter-thread optimization, so it has to be conservative and reload the counter variable after the call and the reload is what prevents the optimization you expect.
Of course, a simple explanation would be that your program is undefined if the signal handler executes, because you should've made counter volatile sig_atomic_t and you should've have synced your inter-thread access to it with either _Atomic or a mutex -- and in an undefined program, anything is possible.
anyone have idea how to log data? It sometimes prints something, but mostly nothing. I have no idea, where is a bug... Also tried without mutex, but it still doesn't work.
Thank you very much
Compiled with gcc -o testtest.c -std=c99 -Wall -Wextra -pedantic -pthread
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void logger(const char *msg) {
pthread_mutex_lock(&lock);
printf("%s", msg);
fflush(stdout);
pthread_mutex_unlock(&lock);
}
void *A(void *arg) {
fprintf(stderr, "AAA");
logger("Inside thread A");
return NULL;
}
void *B(void *arg) {
fprintf(stderr, "BBB");
logger("Inside thread A");
return NULL;
}
pthread_t t_id[2];
int main() {
int s1 = pthread_create(&(t_id[0]), NULL, &A, NULL);
int s2 = pthread_create(&(t_id[1]), NULL, &B, NULL);
if (s1 || s2) {
perror("ERROR: Create thread");
exit(2);
}
// EDIT; THIS WAS MISSING
pthread_join(t_id[0], NULL);
pthread_join(t_id[1], NULL);
return 0;
}
To iterate what #πάντα ῥεῖ said.
You need to join your threads, or wait for all threads to finish execution before you exit the application.
Otherwise the application exits before the threads had a chance to print the messages.
I am using ucontext along with pthread. The below program works OK on Linux, but has failed assertion on Mac.
The problem seems that thread local variables are not correctly accessed after resuming the context from another thread.
The program creates two threads, A and B. A sets the context ready before B could resume the context, for it's synced properly.
It's very appreciated if someone could shed some light on this behavior on mac.
ENV:
clang version 3.7.0 (http://llvm.org/git/llvm.git 8d70064a4ac2ae09b8003173e751cfad9dc15400)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
Program:
#define _XOPEN_SOURCE 800
#include <ucontext.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
static int flag = 0;
void swap(ucontext_t *old, ucontext_t *new)
{
int ret = swapcontext(old, new);
assert(ret == 0);
}
#define SSIZE MINSIGSTKSZ
static char stack[SSIZE];
static ucontext_t a_ctx[2];
static ucontext_t b_ctx[2];
volatile static __thread int bug = 0;
static void func(int b) { }
static void f1 (void)
{
assert(bug == 0);
func(bug);
swap(&a_ctx[1], &a_ctx[0]);
assert(bug == 1);
}
void *thread_a(void *arg)
{
printf("A is %lu\n", pthread_self());
bug = 0;
ucontext_t ctx = a_ctx[1];
getcontext(&ctx);
ctx.uc_stack.ss_sp = stack;
ctx.uc_stack.ss_size = sizeof stack;
makecontext(&ctx, f1, 0);
swap(&a_ctx[0], &ctx);
__atomic_store_n(&flag, 1, __ATOMIC_RELAXED);
sleep(1);
return NULL;
}
void *thread_b(void *arg)
{
printf("B is %lu\n", pthread_self());
bug = 1;
while(__atomic_load_n(&flag, __ATOMIC_RELAXED) == 0) ;
swap(&b_ctx[0], &a_ctx[1]);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t a, b;
pthread_create(&b, NULL, &thread_b, NULL);
pthread_create(&a, NULL, &thread_a, NULL);
pthread_exit(NULL);
}
I am making a program containing a "Server.c" which waits a client to send it a SIGUSR1 msg 10 times, then dies, and a "client.c" which sends a SIGUSR1 msg to the server.
The problem is that if I try to access the siginfo_t* info, I get a segmentation fault.
Note that this is being tested on a Debian ssh server on which I do not have high permissions.
Node that this code works fine on Ubuntu.
Can siginfo_t *info fail due to permission issues? Or is there another issue causing this portability problem. As far as I know libc should be fairly standard throughout any linux distro, possibly unix.
Any Ideas?
Thanks
server.c
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int signo, siginfo_t *info, void * context)
{
puts("SIGNAL RECEIVED");
assert(clients);
clients[counter] = info->si_pid;
++counter;
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SA_SIGINFO);
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
//sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
}
puts("I'm done!");
return 0;
}
client.c:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main(int argc, const char** argv)
{
int server_id;
assert(argc == 2);
server_id = atoi(argv[1]);
assert(server_id > 0);
kill(server_id, SIGUSR1);
return 0;
}
I tried editing server.c to:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int counter = 0;
pid_t *clients = 0;
void on_signal(int sig)
{
puts("SIGNAL RECEIVED");
}
int main()
{
struct sigaction action;
sigset_t set;
int recieveflag = 0;
clients = (pid_t*)malloc(10 * sizeof(pid_t));
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
memset(&action, 0, sizeof(struct sigaction));
action.sa_flags = SA_SIGINFO;
action.sa_handler = on_signal;
sigaction(SIGUSR1, &action, 0);
while (counter < 10) {
sigprocmask(SIG_BLOCK, &set, 0);
sigsuspend(&set);
++counter;
}
puts("I'm done!");
return 0;
}
now it no longer receives the SIGUSR1 event at all.
The basic behavior of sigaction is to call a simple callback like : void (*sa_handler)(int);. So if you want to use the sigaction handle with 3 parameters void (*sa_sigaction)(int, siginfo_t *, void *);, you must set the sa_flags field of your struct sigaction with the flag SA_SIGINFO. Take a look of the man page : http://www.kernel.org/doc/man-pages/online/pages/man2/sigaction.2.html who is clear.
I am trying to study how signal handlers work. I have written code where i cause an alarm signal to raise once in every 100us. But, the signal is not raised. Here is the code :
#include <signal.h>
#include <ucontext.h>
#include <sys/time.h>
#include<unistd.h>
#include<setjmp.h>
#include<stdio.h>
void handler(int signum, siginfo_t *ptr, ucontext_t *old_context)
{
printf("inside handler");
}
int main()
{
struct itimerval itv;
struct sigaction act;
act.sa_handler = handler;
act.sa_flags=SA_RESTART|SA_SIGINFO;
sigaction(SIGVTALRM, &act, 0);
itv.it_interval.tv_sec=0;
itv.it_interval.tv_usec=100;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 100;
setitimer(ITIMER_VIRTUAL, &itv, NULL); //engage timer
int i=0;
while(i<=100)
{
printf("main\n");
i++;
}
}
can some one explain what i am doing wrong?
Thanks
Your loop is probably taking less than 100us to run, try this:
volatile int i=0;
while(i<=100000000)
{
//printf("main\n");
i++;
}
I removed the printf so the output is not flooded, and made i volatile so the compiler won't optimize the loop.