我正在使用SCHED_FIFO和pthread条件变量。
程序由3个线程组成:cpu 0上具有较高优先级的“ main”,cpu 0上也具有“ task_1”的优先级以及cpu 1上具有最低优先级的“ task_2”。
从posix条件变量的角度来看,“主要”是生产者,其他线程是“消费者”。
问题如下:调用广播后,主程序被优先级较低的task_1抢占,然后task_2在主程序之前也完成了执行...
跟踪(总是)是以下跟踪:
[main] creating task_2
[task_2] lock
[task_2] wait
[main] creating task_1
[task_1] lock
[task_1] wait
[main] before lock
[main] before unlock
[task_1] running
[main] after unlock
[task_1] unlock
[task_2] running
[main] finished
[task_2] unlock
using time_ns_t = uint64_t;
constexpr time_ns_t sec_to_us(time_ns_t sec) {
return sec * 1000000;
}
pthread_mutex_t mutex;
void mutex_init() {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
// pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_NONE);
pthread_mutex_init(&mutex, &attr);
}
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
bool ready = false;
//--------------------------------------------------
uint64_t total_usage(const struct rusage& usage) {
uint64_t u_sec = usage.ru_utime.tv_sec;
uint64_t u_micro = usage.ru_utime.tv_usec;
uint64_t s_sec = usage.ru_stime.tv_sec;
uint64_t s_micro = usage.ru_stime.tv_usec;
return (u_sec + s_sec) * 1000000 + (u_micro + s_micro);
}
uint64_t burn_cpu(uint64_t microsec) {
struct rusage usage;
getrusage(RUSAGE_THREAD, &usage);
uint64_t init = total_usage(usage);
uint64_t duration = 0;
while (duration < microsec) {
getrusage(RUSAGE_THREAD, &usage);
duration = total_usage(usage) - init;
}
return duration;
}
//--------------------------------------------------
int set_cpu(int cpu) {
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(cpu, &set);
return sched_setaffinity(0, sizeof(cpu_set_t), &set);
}
int set_rt_priority(int priority) {
struct sched_param sp;
sp.sched_priority = priority;
return sched_setscheduler(0, SCHED_FIFO, &sp);
}
//--------------------------------------------------
void* thread_start_1(void* data) {
set_cpu(0);
set_rt_priority(20);
std::cout << "[task_1] lock\n";
pthread_mutex_lock(&mutex);
while (!ready) {
std::cout << "[task_1] wait\n";
pthread_cond_wait(&cond, &mutex);
}
std::cout << "[task_1] running\n";
burn_cpu(sec_to_us(1));
pthread_mutex_unlock(&mutex);
std::cout << "[task_1] unlock\n";
return nullptr;
}
void* thread_start_2(void* data) {
set_cpu(1);
set_rt_priority(10);
std::cout << "[task_2] lock\n";
pthread_mutex_lock(&mutex);
while (!ready) {
std::cout << "[task_2] wait\n";
pthread_cond_wait(&cond, &mutex);
}
std::cout << "[task_2] running\n";
burn_cpu(sec_to_us(1));
pthread_mutex_unlock(&mutex);
std::cout << "[task_2] unlock\n";
return nullptr;
}
int main(int argc, char* argv[]) {
pthread_t id_1, id_2;
set_cpu(0);
set_rt_priority(50);
burn_cpu(sec_to_us(1));
std::cout << "[main] creating task_2\n";
pthread_create(&id_2, nullptr, thread_start_2, nullptr);
burn_cpu(sec_to_us(1));
std::cout << "[main] creating task_1\n";
pthread_create(&id_1, nullptr, thread_start_1, nullptr);
burn_cpu(sec_to_us(1));
std::cout << "[main] before lock\n";
pthread_mutex_lock(&mutex);
ready = true;
pthread_cond_broadcast(&cond);
std::cout << "[main] before unlock\n";
pthread_mutex_unlock(&mutex);
std::cout << "[main] after unlock\n";
burn_cpu(sec_to_us(1));
std::cout << "[main] finished\n";
pthread_join(id_1, nullptr);
pthread_join(id_2, nullptr);
return 0;
}