I am trying to play with the priority with POSIX. My goal is to have the following program. Two thread are running Thread0 with a priority of 10 and Thread1 with the priority of 50. The Thread1 block in a finite loop (like 3 seconds) and in this time interval Thread0 try to execute himself. The result should be the the Thread0 will be blocked because a thread with higher priority is executing.
My result is that the priority doesn't change the behaviour of the thread... I compile with the following command gcc -Wall -o scheduling scheduling3.c -pthread
and with the sudo su command on ubuntu.
Result :
Prio min = 1, Prio max = 99
SCHED_FIFO
Priority of the thread 0 : 10
SCHED_FIFO
Priority of the thread 1 : 50
Value of test_thread_0 1
Value of test_thread_1 1
Result that I want :
Prio min = 1, Prio max = 99
SCHED_FIFO
Priority of the thread 0 : 10
SCHED_FIFO
Priority of the thread 1 : 50
Value of test_thread_0 1
Value of test_thread_1 1
Program :
// The thread with high priority wil block the thread with low priority
// Run with super user privilege (sudo su with ubuntu)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <pthread.h>
#include <errno.h>
#define NUM_THREADS 2
int test_thread_0 = 0;
int test_thread_1 = 0;
void *BlockThread0(void *threadid) {
test_thread_0 = 1;
}
void *BlockThread1(void *threadid) {
struct timeval start, end;
long secs_used;
gettimeofday(&start, NULL);
test_thread_1 = 1;
while(1) {
gettimeofday(&end, NULL);
secs_used=(end.tv_sec - start.tv_sec); //avoid overflow by subtracting first
if(secs_used > 3)
break;
}
}
int main(int argc, char *argv[]) {
int i, policy;
pthread_t tid[NUM_THREADS];
pthread_attr_t attr[NUM_THREADS];
struct sched_param param[NUM_THREADS], test;
int prio_max, prio_min;
// Get the range of the policy
prio_max = sched_get_priority_max(SCHED_FIFO);
prio_min = sched_get_priority_min(SCHED_FIFO);
printf("Prio min = %d, Prio max = %d \n", prio_min, prio_max);
// Set the different priority
param[0].sched_priority = 10;
param[1].sched_priority = 50;
// Set all the attribute (policy + priority)
for(i = 0; i < NUM_THREADS; i++) {
pthread_attr_init(&attr[i]);
if(pthread_attr_setinheritsched(&attr[i], PTHREAD_EXPLICIT_SCHED) != 0)
fprintf(stderr, "Unable to set EXPLICIT SCHEDULER.\n");
pthread_attr_setdetachstate(&attr[i], PTHREAD_CREATE_JOINABLE);
/* The attribute get the new policy */
if(pthread_attr_setschedpolicy(&attr[i], SCHED_FIFO) != 0)
fprintf(stderr, "Unable to set policy.\n");
/* Test to change the priority of each task */
if(pthread_attr_setschedparam(&attr[i], ¶m[i]) != 0)
fprintf(stderr, "Unable to set priority.\n");
}
// Get all the attribute (policy + priority)
for(i = 0; i < NUM_THREADS; i++) {
// Get the policy
if(pthread_attr_getschedpolicy(&attr[i], &policy) != 0)
fprintf(stderr, "Unable to get policy.\n");
else{
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
else if(policy == SCHED_RR)
printf("SCHED_RR\n");
else if(policy == SCHED_FIFO)
printf("SCHED_FIFO\n");
}
/* Get the priority */
pthread_attr_getschedparam(&attr[i], &test);
printf("Priority of the thread %d : %d \n",i,test.sched_priority);
}
// Thread1 with the most important priority is executing
pthread_create(&tid[1], &attr[1], BlockThread1, (void *)1);
// To be sure that the thread1 is running
sleep(1);
//Thread2 with lower priority attempt to execute himself but he is blocked because thread1 is executing
pthread_create(&tid[0], &attr[0], BlockThread0, (void *)0);
/* now join on each thread */
for(i = 0; i < NUM_THREADS; i++)
pthread_join(tid[i], NULL);
printf("Value of test_thread_0 %d \n",test_thread_0);
printf("Value of test_thread_1 %d \n",test_thread_1);
}
That loop is called a "busy loop", it does not give the OS' scheduler a way to schedule other threads. You should use some variant of sleep().
'The result should be the the Thread0 will be blocked because a thread with higher priority is executing'
No. Not with nearly all hardware commonly available today.
Threads will only remain ready, waiting for execution, if there are more ready/running threads than cores available to run them.
With two threads, you should notice something like you were expecting on a processor with only one core.
They are very rare now.
Related
I'm currently writing a program that takes an array that has randomly generated numbers, and uses multithreading to essentially divide the array in equal parts, then each thread will find the minimum of their respective division of the array. Essentially, I need my parent thread to be blocked (have non-busy waiting for parallel processing efficiency) using semaphores while the child threads are looking for the minimum, however the combination of sem_wait and sem_post is not blocking the parent thread as expected.
I've attempted to change the sem_init parameters to different values, however it seems no matter what I do the parent doesn't actually get blocked.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/timeb.h>
#include <semaphore.h>
#include <stdbool.h>
#include <unistd.h>
#define MAX_SIZE 100000000
#define MAX_THREADS 16
#define RANDOM_SEED 8631
#define MAX_RANDOM_NUMBER 5000
// Global variables
long gRefTime; //For timing
int gData[MAX_SIZE]; //The array that will hold the data
int gThreadCount; //Number of threads
int gDoneThreadCount; //Number of threads that are done at a certain point. Whenever a thread is done, it increments this. Used with the semaphore-based solution
int gThreadMin[MAX_THREADS]; //The minimum value found by each thread
bool gThreadDone[MAX_THREADS]; //Is this thread done? Used when the parent is continually checking on child threads
int indices[MAX_THREADS][3];
// Semaphores
sem_t completed; //To notify parent that all threads have completed or one of them found a zero
sem_t mutex; //Binary semaphore to protect the shared variable gDoneThreadCount
int main(int argc, char *argv[]){
pthread_t tid[MAX_THREADS];
pthread_attr_t attr[MAX_THREADS];
int i, indexForZero, arraySize, min;
// Code for parsing and checking command-line arguments
if(argc != 4){
fprintf(stderr, "Invalid number of arguments!\n");
exit(-1);
}
if((arraySize = atoi(argv[1])) <= 0 || arraySize > MAX_SIZE){
fprintf(stderr, "Invalid Array Size\n");
exit(-1);
}
gThreadCount = atoi(argv[2]);
if(gThreadCount > MAX_THREADS || gThreadCount <=0){
fprintf(stderr, "Invalid Thread Count\n");
exit(-1);
}
indexForZero = atoi(argv[3]);
if(indexForZero < -1 || indexForZero >= arraySize){
fprintf(stderr, "Invalid index for zero!\n");
exit(-1);
}
GenerateInput(arraySize, indexForZero);
CalculateIndices(arraySize, gThreadCount, indices);
InitSharedVars();
SetTime();
// Initialize threads, create threads, and then make the parent wait on the "completed" semaphore
// The thread start function is ThFindMinWithSemaphore
sem_init(&mutex, 0, 1);
sem_init(&completed, 0, 0);
for(i=0; i < gThreadCount; i++){
pthread_attr_init(&attr[i]);
pthread_create(&tid[i],&attr[i],ThFindMinWithSemaphore,&indices[i]);
}
sem_wait(&completed);
if(gThreadDone[i] == true && gThreadMin[i] == min){
for(i=0; i < gThreadCount; i++){
pthread_cancel(tid[i]);
}
}
min = SearchThreadMin();
printf("Threaded FindMin with parent waiting on a semaphore completed in %ld ms. Min = %d\n", GetTime(), min);
void* ThFindMinWithSemaphore(void *param) {
int threadNum = ((int*)param)[0];
int i;
int startIndex = indices[threadNum][1];
int endIndex = indices[threadNum][2];
sem_wait(&completed);
for (i = startIndex; i < endIndex; i++) {
if (gData[i] < gThreadMin[threadNum]){
gThreadMin[threadNum] = gData[i];
}
else if (gData[i] == 0){
sem_post(&completed);
pthread_exit(0);
}
}
sem_wait(&mutex);
gDoneThreadCount++;
sem_post(&mutex);
if (gDoneThreadCount == gThreadCount){
sem_post(&completed);
}
pthread_exit(0);
}
Note that this is not all of the file code that is actually in the file.
I want the main function to wait at the line where it says sem_wait(&completed). The goal is to have the child threads signal the parent by using sem_post when each thread is done searching for their minimum value, or one of the threads has found a zero within the array. Then at that point the main function should continue after receiving that sem_post signal.
As I understand, if the semaphore completed has a count of zero which I have initialized it to that using sem_init(&completed, 0, 0), the caller for sem_wait waits until it receives sem_post from one of the child threads. It appears that my program does not do the wait as expected.
I write a c program to test linux scheduler. this is my code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void Thread1()
{
sleep(1);
int i,j;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
/* for(i=1;i<100;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
}
void Thread2()
{
sleep(1);
int i,j,m;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR\n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
}
void Thread3()
{
sleep(1);
int i,j;
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
/* for(i=1;i<10;i++) */
while(1)
{
for(j=1;j<5000000;j++)
{
}
printf("thread 3\n");
}
printf("Pthread 3 exit\n");
}
int main()
{
int i;
i = getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");
pthread_t ppid1,ppid2,ppid3;
struct sched_param param;
pthread_attr_t attr3,attr1,attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
pthread_create(&ppid3,&attr3,(void *)Thread3,NULL);
pthread_create(&ppid2,&attr2,(void *)Thread2,NULL);
pthread_create(&ppid1,&attr1,(void *)Thread1,NULL);
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
In this program, I create one thread with default attribute and two thread whose schedule policy is SCHED_RR and specific priority. My question is:
When I run the program, I can barly see the output from thread 1. How can this happen ? I think that thread 1 and thread 2 are real time process and thread 3 is a normal process. So thread 3 will never run until thread 1 and thread 2 exit. But In my program thread 1 and thread 2 never exit, so I expect that only thread 2 can actually run. Why I can see the output of thread 2 and thread 3 and can't see the output of thread 1?
Thread 3 can be run because 0.05s is reserved for non-runtime tasks, disable it via echo -1 > /proc/sys/kernel/sched_rt_runtime_us:
The default values for sched_rt_period_us (1000000 or 1s) and
sched_rt_runtime_us (950000 or 0.95s). This gives 0.05s to be used by
SCHED_OTHER (non-RT tasks). These defaults were chosen so that a run-away
realtime tasks will not lock up the machine but leave a little time to recover it. By setting runtime to -1 you'd get the old behaviour back.
sched-rt-group.txt
Thread 1 cannot be run because thread 2 has higher priority (note that 99 is the highest RT priority in pthread calls, this is contradictory to internal Linux numbering and explained here), and round-robin scheduling is only performed within a queue of process with the same priority:
SCHED_RR tasks are scheduled by priority, and within a certain priority they are scheduled in a round-robin fashion. Each SCHED_RR task within a certain priority runs for its allotted timeslice, and then returns to the bottom of the list in its priority array queue.
Understanding the Linux 2.6.8.1 CPU Scheduler
Some notes on how to to find out why this is happening. To do so, we will need source code and dynamic tracer like SystemTap. Switching threads (or more precisely context switch) can be traced via scheduler.ctxswitch probe which is wrapper around sched_switch tracepoint.
Checking source code around that tracepoint says that new task is handled by __schedule function which calls pick_next_task:
3392 next = pick_next_task(rq, prev, cookie);
...
3397 if (likely(prev != next)) {
...
3402 trace_sched_switch(preempt, prev, next);
Crawling into source code leads us to pick_next_task_rt, which, under certain conditions returns NULL instead of our threads. It's SystemTap time!
# stap -e 'probe kernel.function("pick_next_task_rt").return {
if ($return == 0) {
println($rq->rt$) } }' -c ./a.out
...
{.active={...}, .rt_nr_running=2, .highest_prio={...}, .rt_nr_migratory=2, .rt_nr_total=2,
.overloaded=1, .pushable_tasks={...}, .rt_throttled=1, .rt_time=950005330, .rt_runtime=950000000,
.rt_runtime_lock={...}, .rt_nr_boosted=0, .rq=0xffff8801bfc16c40,
.leaf_rt_rq_list={...}, .tg=0xffffffff81e3d480}
SCHED_OTHER
So, it seems that rt_time is greater than 950ms and rt_throttled flag is set when we switch to SCHED_OTHER. Further googling leads to this answer and documentation linked above.
the following proposed code:
which only checks some of the error status values from system functions
shows why the OP is having a problem
follows the axiom: only one statement per line and (at most) one variable declaration per statement.
corrects many of the problems noted by the compiler in the OPs code
Note: this was run on ubuntu linux 16.04
#include <stdio.h>
//#include <unistd.h> -- contents not used
#include <stdlib.h>
#include <pthread.h>
void *Thread1( void *data );
void *Thread2( void *data );
void *Thread3( void *data );
void *Thread1( void *data )
{
(void)data;
sleep(1);
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR 1 \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for( size_t i=0; i<1000; i++ )
{
printf("thread 1\n");
}
printf("Pthread 1 exit\n");
pthread_exit( NULL );
}
void *Thread2( void *data )
{
(void)data;
sleep(1);
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR\n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for( size_t i = 0; i< 1000; i++ )
{
printf("thread 2\n");
}
printf("Pthread 2 exit\n");
pthread_exit( NULL );
}
void *Thread3( void *data )
{
(void)data;
sleep(1);
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(),&policy,¶m);
if(policy == SCHED_OTHER)
printf("SCHED_OTHER\n");
if(policy == SCHED_RR)
printf("SCHED_RR \n");
if(policy==SCHED_FIFO)
printf("SCHED_FIFO\n");
for( size_t i = 0; i<1000; i++ )
{
printf("thread 3\n");
}
printf("Pthread 3 exit\n");
pthread_exit( NULL );
}
int main( void )
{
unsigned i;
i = getuid();
if(i==0)
printf("The current user is root\n");
else
printf("The current user is not root\n");
pthread_t ppid1;
pthread_t ppid2;
pthread_t ppid3;
struct sched_param param;
pthread_attr_t attr3;
pthread_attr_t attr1;
pthread_attr_t attr2;
pthread_attr_init(&attr1);
pthread_attr_init(&attr3);
pthread_attr_init(&attr2);
param.sched_priority = 97;
pthread_attr_setschedpolicy(&attr1,SCHED_RR);
pthread_attr_setschedparam(&attr1,¶m);
pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
param.sched_priority = 98;
pthread_attr_setschedpolicy(&attr2,SCHED_RR);
pthread_attr_setschedparam(&attr2,¶m);
pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
int create3 = pthread_create( &ppid3, &attr3, Thread3, NULL );
if( create3 )
{
fprintf( stderr, "pthread_create for thread 3 failed with status: %d\n", create3 );
//exit( EXIT_FAILURE );
}
int create2 = pthread_create( &ppid2, &attr2, Thread2, NULL );
if( create2 )
{
fprintf( stderr, "pthread_create for thread 2 failed with status: %d\n", create2 );
//exit( EXIT_FAILURE );
}
int create1 = pthread_create( &ppid1, &attr1, Thread1, NULL );
if( create1 )
{
fprintf( stderr, "pthread_create for thread 1 failed with status: %d\n", create1 );
//exit( EXIT_FAILURE );
}
pthread_join(ppid3,NULL);
pthread_join(ppid2,NULL);
pthread_join(ppid1,NULL);
pthread_attr_destroy(&attr3);
pthread_attr_destroy(&attr2);
pthread_attr_destroy(&attr1);
return 0;
}
running the program as a normal user results in:
The current user is not root
pthread_create for thread 2 failed with status: 1
pthread_create for thread 1 failed with status: 1
SCHED_OTHER
thread 3 <-- repeats 1000 times
Pthread 3 exit
running the program as root results in:
The current user is root
SCHED_RR
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
thread 2
SCHED_OTHER
thread 3
thread 3
thread 3
thread 3
thread 3
thread 3
thread 2
SCHED_RR 1
thread 1
thread 1
thread 2
thread 3
thread 3
thread 3
thread 2
thread 1
thread 1
thread 1
thread 1
thread 1
... continues for a total of 3000 lines and
... as each thread completes it outputs:
pthread 1 exit -OR- pthread 2 exit -OR- pthread 3 exit
To answer the OPs questions:
Every time the REAL TIME threads call printf() other threads get a chance to run. In part, this is due to the context switching being performed including the context switching to switch between user and OS processes.
I'm currently working on custom thread scheduler project that uses pthreads in C. I have been struggling conceptually with it but am finally getting the behavior I expect to see, save for the segmentation fault.
My job is to register five child threads and schedule each one based on the order of their IDs stored in an array. What I do is call pthread_mutex_lock and tell whichever child thread that is not to be scheduled first to wait. I do some stuff to my counter to keep track of when the next child should be scheduled and after one child thread increments counter to five it should wake up other threads and do the same thing for as many times as main loop is defined.
all variables:
#define NTHREADS 5 /* Number of child threads */
#define NUM_LOOPS 10 /* Number of local loops */
#define SCHEDULE_INTERVAL 1 /* thread scheduling interval */
#define errexit(code,str) fprintf(stderr,"%s: %s\n",(str),strerror(code));exit(1);
int schedule_vector[NTHREADS]; /* The thread schedule vector */
int flag = 0;
pthread_cond_t cv; // condtitional variable
pthread_mutex_t mtx; // mutex semaphore 1
int globalcounter = 0;
int currentThread;
#define TASK_LIMIT 6
here is parent thread:
int main(int argc,char *argv[])
{
int i;
int worker;
int ids[NTHREADS];
int errcode;
int *status;
int policy;
pthread_t threads[NTHREADS];
/* Create child threads --------------------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
ids[worker] = worker;
printf("creating child thread using id %d\n", worker);
/* Create a child thread ----------------------------------------- */
pthread_create (
&threads[worker],
NULL,
my_thread,
&ids[worker]);
}
/* Initialize the thread schedule vector -------------------------- */
schedule_vector[0] = 0; /* First thread to be executed (0) */
schedule_vector[1] = 1; /* Second thread to be exceuted (1) */
schedule_vector[2] = 2; /* Third thread to be executed (2) */
schedule_vector[3] = 3; /* Fourth thread to be executed (3) */
schedule_vector[4] = 4; /* Fifth thread to be executed (4) */
signal(SIGALRM, clock_interrupt_handler);
alarm(SCHEDULE_INTERVAL);
printf("handler set up\n");
/* Reap the threads as they exit ----------------------------------- */
for (worker = 0; worker < NTHREADS; worker++)
{
/* Wait for thread to terminate --- */
if (errcode=pthread_join(threads[worker],(void *) &status))
{ errexit(errcode,"pthread_join"); }
/* Check thread's exit status and release its resources -------- */
if (*status != worker)
{
fprintf(stderr,"thread %d terminated abnormally\n",worker);
exit(1);
}
}
/* The main (parent) thread terminates itself ---------------------- */
return(0);
}
Here is the child thread function:
void *my_thread(void * arg)
{
long int i;
long int counter;
int myid=*(int *) arg;
counter = 0;
printf("\nI am thread #%d\n\n", myid);
/* Main loop ------------------------------------------ */
for (i = 0; i < NUM_LOOPS; i++)
{
currentThread = myid;
pthread_mutex_lock(&mtx);
while(myid != schedule_vector[flag]){
pthread_cond_wait(&cv, &mtx);
}
counter++;
globalcounter = counter;
printf("Thread: %d is running ...\n", myid);
usleep(100000);
}
return arg;
}
and here is my interrupt handler:
void clock_interrupt_handler(void)
{
printf("scheduler started ++++++++++++++++++++++++++++++++++ \n");
if (currentThread == schedule_vector[flag]) {
printf("scheduled thread received: thread %d, and it's counter is at %d\n", currentThread, globalcounter);
while(globalcounter < TASK_LIMIT){
if(globalcounter == 5){
flag++;
pthread_cond_broadcast(&cv);
}
pthread_mutex_unlock(&mtx);
alarm(SCHEDULE_INTERVAL);
}
} else {
printf("unscheduled thread received, putting thread %d with count %d to sleep...\n", currentThread, globalcounter);
alarm(SCHEDULE_INTERVAL);
}
}
This is the output:
scheduler started ++++++++++++++++++++++++++++++++++
scheduled thread received: thread 0, and it's counter is at 1
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Thread: 0 is running ...
Segmentation fault (core dumped)
It basically repeats this behavior, but for each thread. I'd like to understand what is exactly causing the seg fault
Seems pthread_mutex_lock/pthread_mutex_unlock do not pair.
The correct code looks like
pthread_mutex_lock()
pthread_cond_broadcast()
pthread_mutex_unlock()
pthread_mutex_lock()
pthread_cond_wait()
pthread_mutex_unlock()
I'm trying to synchronize multiple (7) threads. I thought I understood how they work until I was trying it on my code and my threads were still printing out of order. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
void *text(void *arg);
long code[] = {4,6,3,1,5,0,2}; //Order in which to start threads
int num = 0;
pthread_mutex_t lock; //Mutex variable
int main()
{
int i;
pthread_t tid[7];
//Check if mutex worked
if (pthread_mutex_init(&lock, NULL) != 0){
printf("Mutex init failed\n");
return 1;
}
//Initialize random number generator
time_t seconds;
time(&seconds);
srand((unsigned int) seconds);
//Create our threads
for (i=0; i<7; i++)
pthread_create(&tid[i], NULL, text, (void*)code[i]);
//Wait for threads to finish
for (i=0; i<7; i++){
if(pthread_join(tid[i], NULL)){
printf("A thread failed to join\n");
}
}
//Destroy mutex
pthread_mutex_destroy(&lock);
//Exit main
return 0;
}
void *text (void *arg)
{
//pthread_mutex_lock(&lock); //lock
long n = (long) arg;
int rand_sec = rand() % (3 - 1 + 1) + 1; //Random num seconds to sleep
while (num != n) {} //Busy wait used to wait for our turn
num++; //Let next thread go
sleep(rand_sec); //Sleep for random amount of time
pthread_mutex_lock(&lock); //lock
printf("This is thread %d.\n", n);
pthread_mutex_unlock(&lock); //unlock
//Exit thread
pthread_exit(0);
}
So here I am trying to make threads 0-6 print IN ORDER but right now they are still scrambled. The commented out mutex lock is where I originally had it, but then moved it down to the line above the print statement but I'm having similar results. I am not sure where the error in my mutex's are, could someone give a hint or point me in the right direction? I really appreciate it. Thanks in advance!
You cannot make threads to run in order with only a mutex because they go in execution in an unpredictable order.
In my approach I use a condition variable and a shared integer variable to create a queueing system. Each thread takes a number and when the current_n number is equal to the one of the actual thread, it enters the critical section and prints its number.
#include <pthread.h>
#include <stdio.h>
#define N_THREAD 7
int current_n = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t number = PTHREAD_COND_INITIALIZER;
void *text (void *arg) {
int i = (int)arg;
pthread_mutex_lock(&mutex);
while ( i > current_n ) {
pthread_cond_wait(&number, &mutex);
}
//i = current_n at this point
/*I use stderr because is not buffered and the output will be printed immediately.
Alternatively you can use printf and then fflush(stdout).
*/
fprintf(stderr, "I'm thread n=%d\n", i);
current_n ++;
pthread_cond_broadcast(&number);
pthread_mutex_unlock(&mutex);
return (void*)0;
}
int main() {
pthread_t tid[N_THREAD];
int i = 0;
for(i = 0; i < N_THREAD; i++) {
pthread_create(&tid[i], NULL, text, (void *)i);
}
for(i = 0; i < N_THREAD; i++) {
if(pthread_join(tid[i], NULL)) {
fprintf(stderr, "A thread failed to join\n");
}
}
return 0;
}
The output is:
I'm thread n=0
I'm thread n=1
I'm thread n=2
I'm thread n=3
I'm thread n=4
I'm thread n=5
I'm thread n=6
Compile with
gcc -Wall -Wextra -O2 test.c -o test -lpthread
Don't worry about the warnings.
I'm trying to write safe SIGINT handling for my multithreaded application and I'm using sleep() function to simulate entering "unsafe" zone - a place where a thread shouldn't be cancelled. Here's my code:
Global variables:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
pthread_mutex_t *global_mutex;
pthread_mutex_t **thread_mutexes;
pthread_mutex_t *firm_mutex;
pthread_attr_t *attr;
Thread:
void *thread(void *data)
{
int local_tid = *(int *) data;
printf("Starting thread %d\n", local_tid);
for (;;) {
pthread_mutex_lock(thread_mutexes[local_tid]);
int scnds = rand() % 5 + 1;
printf("%d locked\nSleeping for: %d seconds\n", local_tid, scnds);
sleep(scnds);
printf("%d woken up!\n", local_tid);
pthread_mutex_unlock(thread_mutexes[local_tid]);
}
}
Thread creation:
int main()
{
int n;
scanf("%d", &n);
printf("Starting signal handler with %d threads...\n",n);
global_mutex = malloc(sizeof(pthread_mutex_t));
firm_mutex = malloc(sizeof(pthread_mutex_t));
thread_mutexes = malloc(n * sizeof(pthread_mutex_t *));
for (int i = 0; i < n; i++) {
thread_mutexes[i] = malloc(sizeof(pthread_mutex_t));
}
attr = malloc(sizeof(pthread_attr_t));
if (pthread_attr_init(attr) != 0 ) {
perror("attrinit\n");
exit(1);
}
if (pthread_attr_setdetachstate (attr,PTHREAD_CREATE_JOINABLE) != 0) {
perror("setdetach\n");
exit(1);
}
for (int i = 0; i < n; i++) {
pthread_t tid;
if (pthread_mutex_init (thread_mutexes[i], 0) != 0) {
perror("mutexinit\n");
exit(1);
}
int *tdata = malloc(sizeof(int));
*tdata = i;
if (pthread_create (&tid, attr, watek, tdata) != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_join (tid, 0) != 0) {
perror("join\n");
exit(1);
}
}
return 0;
}
So you would think that after launching with 10 threads, first thread should go to sleep immedietely and in the meantime another should start execution. Unfortuntely, after launching the program with 10 threads I get an output like this:
Starting signal handler with 10 threads...
Starting thread 0
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked
sleeping for: 2 seconds
0 woken up!
0 locked
sleeping for: 3 seconds
0 woken up!
0 locked
sleeping for: 1 seconds
0 woken up!
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked
Basically thread 0 steals all the time! Why aren't other threads executed when 0 sleeps?
if (pthread_create (&tid, attr, watek, tdata) != 0) {
perror("pthread_create");
exit(1);
}
if (pthread_join (tid, 0) != 0) {
perror("join\n");
exit(1);
}
You're creating the first thread and then waiting to pthread_join with it before creating the next one. The next loop iteration, therefore, (creating the next thread) won't happen until the first thread terminates.
If you want all the threads to start right away, just create and start them in the first loop - deal with waiting for them to complete later.