Start two threads with policy SCHED_RR and priority 45.
One thread's affinity is 0x0004, and another is 0x0008.(my computer contains four cpu cores. system is CentOS 7, not a virtual machine.)
The subTask is simple:
spinning trylock in the while.
call printf show the information.
free the lock.
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>
#define CHECK_ERROR(call)\
do{\
int _error = (call);\
if(_error != 0){\
printf("*** Error *** at [%s:%d] error=%d \n", __FILE__, __LINE__, _error);\
}\
}while(0)
int getThreadCores(pthread_t thread, int *cores);
int getThreadPP(pthread_t thread, int *policy, int *priority);
int setThreadAttrCores(pthread_attr_t *attr, int cores);
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority);
#define SUB_THREAD_NUM (2)
static int threadsId[SUB_THREAD_NUM];
static pthread_t subThreads[SUB_THREAD_NUM];
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *subTask(void *data)
{
int id = *(int*)data;
int policy=0, priority=0, cores=0;
CHECK_ERROR(getThreadCores(pthread_self(), &cores));
CHECK_ERROR(getThreadPP(pthread_self(), &policy, &priority));
printf("the sub thread %d, cores 0x%x, policy %d, priority %d\n",
id,cores,policy,priority);
int n = 1024*10;
int i;
for(i=0;i<n;++i)
{
while(pthread_mutex_trylock(&lock)){}
printf("the sub thread %d, out put %d\n",id,i);
CHECK_ERROR(pthread_mutex_unlock(&lock));
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_attr_t attr;
CHECK_ERROR(pthread_attr_init(&attr));
int i;
for(i=0;i<SUB_THREAD_NUM;++i)
{
threadsId[i] = i;
CHECK_ERROR(setThreadAttrCores(&attr, 0x0004<<i));
CHECK_ERROR(setThreadAttrPP(&attr, SCHED_RR, 1));
CHECK_ERROR(pthread_create(&subThreads[i],&attr,subTask,threadsId+i));
}
CHECK_ERROR(pthread_attr_destroy(&attr));
for(i=0;i<SUB_THREAD_NUM;++i)
{
CHECK_ERROR(pthread_join(subThreads[i],NULL));
}
printf("multiThreadTest success\n");
return 0;
}
int getThreadCores(pthread_t thread, int *cores)
{
int error = 0;
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
int _cores = 0;
cpu_set_t mask;
CPU_ZERO(&mask);
error = pthread_getaffinity_np(thread, sizeof(cpu_set_t), &mask);
if(error == 0)
{
int i;
for(i=0;i<cpuNum;++i)
{
if(CPU_ISSET(i, &mask))
{
_cores |= (0x1 << i);
}
}
}
*cores = _cores;
return error;
}
int getThreadPP(pthread_t thread, int *policy, int *priority)
{
int error = 0;
struct sched_param sp;
error = pthread_getschedparam(thread,policy,&sp);
*priority = sp.sched_priority;
return error;
}
static void setCpuSetMask(cpu_set_t *mask, int cores)
{
int cpuNum = sysconf(_SC_NPROCESSORS_CONF);
CPU_ZERO(mask);
int i;
for(i=0;i<cpuNum;++i)
{
if(((cores>>i)&0x1) == 1)
{
CPU_SET(i, mask);
}
}
}
int setThreadAttrCores(pthread_attr_t *attr, int cores)
{
cpu_set_t mask;
if(cores<0)cores=0xFFFFFFFF;
setCpuSetMask(&mask,cores);
return pthread_attr_setaffinity_np(attr, sizeof(cpu_set_t), &mask);
}
int setThreadAttrPriority(pthread_attr_t *attr, int priority)
{
struct sched_param sp;
sp.sched_priority = priority;
return pthread_attr_setschedparam(attr,&sp);
}
int setThreadAttrPP(pthread_attr_t *attr, int policy, int priority)
{
int error = 0;
//firstly, set the inherit to PTHREAD_EXPLICIT_SCHED
error |= pthread_attr_setinheritsched(attr,PTHREAD_EXPLICIT_SCHED);
error |= pthread_attr_setschedpolicy(attr,policy);
error |= setThreadAttrPriority(attr,priority);
return error;
}
compile: gcc -Wall -O3 -lpthread multiThreadTest.c -o multiThreadTest
My question is: the program blocked, one thread blocked in printf and another blocked in spinning trylock, why?
If I change the policy to SCHED_OTHER and the priority to 0, the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to CHECK_ERROR(pthread_mutex_lock(&lock)); the program unblocked.
If I change the while(pthread_mutex_trylock(&lock)){} to while(pthread_mutex_trylock(&lock)){usleep(1);} the program unblocked.
And if I change the printf to fprintf, the program unblocked.
And if I run the same program on Ubuntu system, it is unblocked.
Related
I have written a code for real-time logging. Here's the pseudo-code:
initialize Q; //buffer structure stores values to be printed
log(input)
{
push input to Q;
}
printLog() //infinte loop
{
loop(1)
{
if(Q is not empty)
{
values = pop(Q);
msg = string(values); //formating values into a message string
print(msg);
}
}
}
mainFunction()
{
loop(1)
{
/*
insert operations to be performed
*/
log(values); //log function called
}
}
main()
{
Create 4 threads; //1 mainFunction and 3 printLog
Bind them to CPUs;
}
I'm using atomic operations instead of locks.
When I print the output to the console, I see that each thread prints consecutively for a while. This must mean that once a thread enters printLog(), the other threads are inactive for a while.
What I want instead is while one thread is printing, another thread formats the next value popped from Q and prints it right after. How can this be achieved?
EDIT: I've realized the above information isn't sufficient. Here are some other details.
Buffer structure Q is a circular array of fixed size.
Pushing information to Q is faster than popping+printing. So by the time the Buffer structure is full, I want most of the information to be printed.
NOTE: mainFunction thread shouldn't wait to fill Buffer when it is full.
I'm trying to utilize all the threads at a given time. Currently, after one thread prints, the same thread reads and prints the next value (this means the other 2 threads are inactive).
Here's the actual code:
//use gcc main.c -o run -pthread
#define _GNU_SOURCE
#include <unistd.h>
#include <stdint.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <math.h>
#include <signal.h>
#include <stdlib.h>
#define N 3
/* Buffer size */
#define BUFFER_SIZE 1000
struct values
{
uint64_t num;
char msg[20];
};
struct values Q[BUFFER_SIZE];
int readID = -1;
int writeID = -1;
int currCount = 0;
void Log(uint64_t n, char* m)
{
int i;
if (__sync_fetch_and_add(&currCount,1) < BUFFER_SIZE)
{
i = __sync_fetch_and_add(&writeID,1);
i = i%BUFFER_SIZE;
Q[i].num = n;
strcpy(Q[i].msg, m);
}
else __sync_fetch_and_add(&currCount,-1);
}
void *printLog(void *x)
{
int thID = *((int*)(x));
int i;
while(1)
{
if(__sync_fetch_and_add(&currCount,-1)>=0)
{
i = __sync_fetch_and_add(&readID,1);
i = i%BUFFER_SIZE;
printf("ThreadID: %2d, count: %10d, message: %15s\n",thID,Q[i].num,Q[i].msg);
}
else __sync_fetch_and_add(&currCount,1);
}
}
void *mainFunction()
{
uint64_t i = 0;
while(1)
{
Log(i,"Custom Message");
i++;
usleep(50);
}
}
int main()
{
/* Set main() Thread CPU */
cpu_set_t cpusetMain;
CPU_ZERO(&cpusetMain);
CPU_SET(0, &cpusetMain);
if(0 != pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpusetMain))
printf("pthread_setaffinity_np failed for CPU: 0\n");
int LogThID[N+1];
pthread_t LogThreads[N+1];
/* Create Threads */
if (pthread_create(&LogThreads[0], NULL, &mainFunction, NULL) != 0){return 0;}
for(int i=1; i<N+1 ; i++)
{
LogThID[i] = i;
if (pthread_create(&LogThreads[i], NULL, &printLog, &LogThID[i]) != 0){return i;}
}
/* Set CPUs */
cpu_set_t cpuset[N+1];
for(int i=0; i<N+1; i++)
{
CPU_ZERO(&cpuset[i]);
CPU_SET(i+1, &cpuset[i]);
if(0 != pthread_setaffinity_np(LogThreads[i], sizeof(cpu_set_t), &cpuset[i]))
printf("pthread_setaffinity_np failed for CPU: %d\n", i+1);
}
struct sched_param param[N+1];
for(int i=0; i<N+1; i++)
{
param[i].sched_priority = 91;
if(0 != pthread_setschedparam(LogThreads[i],SCHED_FIFO,¶m[i]))
printf("pthread_setschedparam failed for CPU: %d\n", i);
}
/* Join threads */
for(int i=0; i<N+1; i++)
{
pthread_join(LogThreads[i], NULL);
}
return 0;
}
I'm implementing a rt-thread using SCHED_DEADLINE. I'm trying to catch a SIGXCPU-signal,
if the thread exceeds the specified sched_runtime. To my understanding of the manpage, this can be achived by setting the SCHED_FLAG_DL_OVERRUN-flag. However, in the example program below, no signal is received (on the third iteration). According to the kernelshark-plot, the thread is suspended after it reaches its runtime but no signal is created.
Is my understanding of the SCHED_FLAG_DL_OVERRUN-flag correct? If not, is there another way to detect, if a thread exceeds the specified runtime, without measuring the time after each iteration?
My kernel version is 5.4.3-rt1-1-rt #1 SMP PREEMPT_RT.
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/types.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sched.h>
#define gettid() syscall(__NR_gettid)
#define SCHED_DEADLINE 6
/* XXX use the proper syscall numbers */
#ifdef __x86_64__
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315
#endif
#ifdef __i386__
#define __NR_sched_setattr 351
#define __NR_sched_getattr 352
#endif
#ifdef __arm__
#define __NR_sched_setattr 380
#define __NR_sched_getattr 381
#endif
static volatile int done;
struct sched_attr {
__u32 size;
__u32 sched_policy;
__u64 sched_flags;
/* SCHED_NORMAL, SCHED_BATCH */
__s32 sched_nice;
/* SCHED_FIFO, SCHED_RR */
__u32 sched_priority;
/* SCHED_DEADLINE (nsec) */
__u64 sched_runtime;
__u64 sched_deadline;
__u64 sched_period;
};
int sched_setattr(pid_t pid,
const struct sched_attr *attr,
unsigned int flags)
{
return syscall(__NR_sched_setattr, pid, attr, flags);
}
int sched_getattr(pid_t pid,
struct sched_attr *attr,
unsigned int size,
unsigned int flags)
{
return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
void set_rt(int pid, unsigned long runtime, unsigned long period, unsigned long deadline){
struct sched_attr attr;
unsigned int flags = 0;
attr.size = sizeof(attr);
attr.sched_flags = SCHED_FLAG_DL_OVERRUN;
attr.sched_nice = 0;
attr.sched_priority = 0;
attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = runtime;
attr.sched_period = period;
attr.sched_deadline = deadline;
int ret = sched_setattr(pid, &attr, 0);
if (ret < 0) {
done = 0;
perror("sched_setattr");
exit(-1);
}
struct sched_attr param;
ret = sched_getattr(pid, ¶m, sizeof(param), 0);
if (ret < 0) {
done = 0;
perror("sched_getattr");
exit(-1);
}
}
void sig_handler(int signo)
{
if (signo == SIGXCPU)
printf("received SIGXCPU\n");
}
int main (void) {
printf("MY PID: %d\n", getpid());
set_rt(gettid(), 500000000Ul, 1000000000Ul, 1000000000Ul);
struct sigaction s;
bzero(&s, sizeof(s));
s.sa_handler = sig_handler;
sigaction (SIGXCPU, &s, NULL);
//test signal handler
kill(getpid(), SIGXCPU);
int i = 0;
while (1) {
i++;
printf("Loop Number %d\n", i);
int k = 900000000;
if (i == 3) {
while (k > 0) k--;
}
sched_yield();
}
}
I have to do for University a project about UDP, where i have to guarantee reliable communication; for packets, i want use timer_gettime() and timer_Settime() functions, because i can queue signals and i can associate to them a timer; in particular, struct sigevent has a field which union sigval where i can pass value to handler when signal arrived; I would like to take advantage of this passing to handler number of packets for which timer expired; I have a problem, and I've done a simple program to verify this; when I start timer, i can disarm it setting it_value of struct sigevent to 0; but data doesn't change; if I send 100 signal, header receives only data of first signal. This is my code:
#include <signal.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
int d;
void err_exit(char* str)
{
perror(str);
exit(EXIT_FAILURE);
}
void sighandler(int sig, siginfo_t *si, void *uc)
{
(void) sig;
(void) uc;
d = si->si_value.sival_int;
}
void handle_signal(struct sigaction* sa)
{
sa->sa_flags = SA_SIGINFO;
sa->sa_sigaction = sighandler;
sigemptyset(&sa->sa_mask);
if (sigaction(SIGRTMAX,sa,NULL) == -1)
err_exit("sigaction");
}
void create_timer(struct sigevent* sev,timer_t* timer_id,int i)
{
union sigval s;
s.sival_int = i;
printf("value: %d\n",i);
sev->sigev_notify = SIGEV_SIGNAL;
sev->sigev_signo = SIGRTMAX;
sev->sigev_value = s;
timer_create(CLOCK_REALTIME,sev,timer_id);
}
void set_timer(timer_t timer_id,struct itimerspec* ts)
{
if(ts == NULL)
printf("itimerspec null\n");
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
void initialize_timerspec(struct itimerspec* ts)
{
ts->it_value.tv_sec = 2;
ts->it_value.tv_nsec = 5;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
}
void reset_timer(timer_t timer_id, struct itimerspec* ts)
{
ts->it_value.tv_sec = 0;
ts->it_value.tv_nsec = 0;
ts->it_interval.tv_sec = 0;
ts->it_interval.tv_nsec = 0;
if (timer_settime(timer_id, 0, ts, NULL) == -1){
printf("errno code: %d\n",errno);
err_exit("timer_settime");
}
}
int main()
{
struct sigaction sa;
struct itimerspec ts[2];
struct sigevent sev[2];
timer_t timer_id[2];
handle_signal(&sa);
create_timer(sev,timer_id,0);
initialize_timerspec(ts);
set_timer(timer_id,ts);
reset_timer(timer_id,ts);
create_timer(sev + 1,timer_id + 1,1);
initialize_timerspec(ts + 1);
set_timer(timer_id,ts + 1);
printf("id1: %ju id2: %ju\n",timer_id[0],timer_id[1]);
sleep(10);
printf("d = %d\n",d);
exit(EXIT_SUCCESS);
}
I disarm first timer, and send another signal; but handler receives data associated to first signal, because it prints 0. Is there a way to send to overwrite data, sending to handler data of second signal(in this case 1)?
so im trying to get this program with semaphores to work.
finally got rid of all of the errors, and now its giving me a core dump issue?
trying to figure out what im doing wrong, been working this all morning and cant seem to find the issue.
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFF_SIZE 20
char buffer[BUFF_SIZE];
int nextIn = 0;
int nextOut = 0;
//char sem_name1[] = "mutex";
//char sem_name2[] = "empty_slots";
//char sem_name3[] = "full_slots";
sem_t *empty_slots;
sem_t *full_slots;
sem_t *mutex;
typedef struct {
char buffer[BUFF_SIZE];
int nextIn;
int nextOut;
} shared_data;
void Put(char item){
sem_wait(empty_slots);
sem_wait(mutex);
buffer[nextIn] = item;
nextIn = (nextIn + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Producing %c ...\n", item);
sem_post(full_slots);
}
void * Producer(){
int i;
for(i = 0; i < 15; i++){
sleep(rand()%6);
Put((char)('A'+ i % 26));
}
}
void Get(char item){
sem_wait(full_slots);
sem_wait(mutex);
item= buffer[nextOut];
nextOut = (nextOut + 1) % BUFF_SIZE;
sem_post(mutex);
printf("Consuming %c ...\n", item);
sem_post(empty_slots);
}
void * Consumer(){
int i;
char item;
for(i = 0; i < 15; i++){
sleep(rand()%6);
Get(item);
}
}
void main(){
sem_init(empty_slots, 0, 1);
sem_init(full_slots, 0, BUFF_SIZE);
sem_init(mutex, 0, 1);
/* Initialize semaphores */
pthread_t pid, cid;
pthread_create(&pid, NULL, Producer, NULL);
pthread_create(&cid, NULL, Consumer, NULL);
// create more consumer & producer threads.
pthread_join(pid, NULL);
pthread_join(cid, NULL);
}
when i use gdb i get the error
(gdb)
Id Target Id Frame
* 1 Thread 0xb7de8700 (LWP 3567) "labp2" __new_sem_init (sem=0x0, pshared=0, value=1)
at sem_init.c:60
(gdb)
I am trying to solve the producer consumer problem using pthreads and semaphores. At the moment, neither of the threads seem to execute and even main isn't printing out a printf, it seems like the process is waiting for input. (so all that happens is, blinking cursor, then I press ctrl+c to end the process because nothing is happening). I have tested get_rand_num and that works. I am compiling with clang -Wall -std=c99 -lpthread -o randnumgen randnumgen.c
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <stdint.h>
#include "sema.c"
typedef struct buffer {
uint64_t *buffer;
int max_size;
int min_fill_lvl;
uint64_t *first;
uint64_t *last;
int size;
semaphore produce;
semaphore consume;
} buffer;
void *producer();
void *consumer();
uint64_t get_rand_num();
void init_buffer();
void cleanup_buffer();
void put_buffer();
uint64_t get_buffer();
int exit1=0;
buffer buf;
int main(){
initialize(&buf.produce, 0);
initialize(&buf.consume, 0);
pthread_t producerThread;
pthread_t consumerThread;
printf("test");
pthread_create(&producerThread, NULL, producer, (void *) &buf);
pthread_create(&consumerThread, NULL, consumer, (void *) &buf);
vacate(&buf.produce);
pthread_join(producerThread, NULL);
pthread_join(consumerThread, NULL);
return 1;
}
void *producer(buffer *buf){
printf("in producer");
init_buffer(&buf, 2, 1);
while (1){
procure(&buf->produce);
uint64_t ret = get_rand_num();
put_buffer(&buf, ret);
vacate(&buf->consume);
}
cleanup_buffer(&buf);
pthread_exit(NULL);
}
void *consumer(buffer *buf){
printf("in consumer");
while (1){
procure(&buf->consume);
uint64_t ret = get_buffer(&buf);
printf("%i", (int) ret);
vacate(&buf->produce);
}
pthread_exit(NULL);
}
uint64_t get_rand_num(){
FILE *rand = NULL;
rand = fopen("/dev/random", "r");
uint64_t num;
//static const size_t size = sizeof(uint64_t);
fread(&num, sizeof(num), 1, rand); //returns -1 if fails i believe
//printf("%i\n", (int) num);
return num;
}
void init_buffer(buffer *buf, int max, int min){
buf->buffer = malloc(sizeof(uint64_t) * max);
buf->size = 0;
buf->min_fill_lvl = min;
buf->max_size = max;
}
void cleanup_buffer(buffer *buf){
free(&buf->buffer);
}
void put_buffer(buffer *buf, uint64_t *num){
if (buf->size < buf->max_size){
*(buf->last++) = *num;
buf->size++;
}
printf("successfully placed num in buffer");
}
uint64_t get_buffer(buffer *buf){
if ((buf->size - 1) <= buf->min_fill_lvl){
buf->size--;
int ret = *buf->first;
buf->first++;
return ret;
}
return 0;
}
This is my semaphore code:
// semaphore setup
void initialize(semaphore *sp, int startVal){
pthread_mutex_init(&sp->lock, NULL);
sp->vacancy = startVal; //starting value for semaphore
pthread_cond_init(&sp->condition, NULL);
}
//destroys semaphore
void destruct(semaphore *sp){
pthread_mutex_destroy(&sp->lock);
pthread_cond_destroy(&sp->condition);
}
//waits until semaphore is available
void procure(semaphore *sp){
pthread_mutex_lock(&sp->lock);
while(sp->vacancy <= 0){
pthread_cond_wait(&sp->condition, &sp->lock);
}
sp->vacancy--;
pthread_mutex_unlock(&sp->lock);
}
//increments vacancy value signalling that a position has been freed
void vacate(semaphore *sp){
pthread_mutex_lock(&sp->lock);
sp->vacancy++;
pthread_cond_signal(&sp->condition);
pthread_mutex_unlock(&sp->lock);
}