Why is printf blocked by while(trylock) on CentOS 7?

Viewed 121

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:

  1. spinning trylock in the while.
  2. call printf show the information.
  3. 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?

enter image description here

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.

0 Answers
Related