【发布时间】:2018-05-23 18:47:24
【问题描述】:
在 Linux 内核 4.4.0-57 上使用 C++11,我试图在同一个内核上运行固定 (pthread_setaffinity_np) 的两个忙循环进程(比如 p1、p2)和使用 POSIX 信号量 (semaphore.h) 和 sched_yield() 确保交错执行顺序。但效果并不好。
下面是父代码(父任务),它产生 2 个进程,每个进程都执行子任务代码。
#include <stdio.h>
#include <cstdlib>
#include <errno.h> // errno
#include <iostream> // cout cerr
#include <semaphore.h> // semaphore
#include <fcntl.h> // O_CREAT
#include <unistd.h> // fork
#include <string.h> // cpp string
#include <sys/types.h> //
#include <sys/wait.h> // wait()
int init_semaphore(){
std::string sname = "/SEM_CORE";
sem_t* sem = sem_open ( sname.c_str(), O_CREAT, 0644, 1 );
if ( sem == SEM_FAILED ) {
std::cerr << "sem_open failed!\n";
return -1;
}
sem_init( sem, 0, 1 );
return 0;
}
// Fork and exec child-task.
// Return pid of child
int fork_and_exec( std::string pname, char* cpuid ){
int pid = fork();
if ( pid == 0) {
// Child
char* const params[] = { "./child-task", "99", strdup( pname.c_str() ), cpuid, NULL };
execv( params[0], params );
exit(0);
}
else {
// Parent
return pid;
}
}
int main( int argc, char* argv[] ) {
if ( argc <= 1 )
printf( "Usage ./parent-task <cpuid> \n" );
char* cpuid = argv[1];
std::string pnames[2] = { "p111", "p222" };
init_semaphore();
int childid[ 2 ] = { 0 };
int i = 0;
for( std::string pname : pnames ){
childid[ i ] = fork_and_exec( pname, cpuid );
}
for ( i=0; i<2; i++ )
if ( waitpid( childid[i], NULL, 0 ) < 0 )
perror( "waitpid() failed.\n" );
return 0;
}
子任务代码如下所示:
#include <cstdlib>
#include <stdio.h>
#include <sched.h>
#include <pthread.h>
#include <stdint.h>
#include <errno.h>
#include <semaphore.h>
#include <iostream>
#include <sys/types.h>
#include <fcntl.h> // O_CREAT
sem_t* sm;
int set_cpu_affinity( int cpuid ) {
pthread_t current_thread = pthread_self();
cpu_set_t cpuset;
CPU_ZERO( &cpuset );
CPU_SET( cpuid, &cpuset );
return pthread_setaffinity_np( current_thread,
sizeof( cpu_set_t ), &cpuset );
}
int lookup_semaphore() {
sm = sem_open( "/SEM_CORE", O_RDWR );
if ( sm == SEM_FAILED ) {
std::cerr << "sem_open failed!" << std::endl ;
return -1;
}
}
int main( int argc, char* argv[] ) {
printf( "Usage: ./child-task <PRIORITY> <PROCESS-NAME> <CPUID>\n" );
printf( "Setting SCHED_RR and priority to %d\n", atoi( argv[1] ) );
set_cpu_affinity( atoi( argv[3] ) );
lookup_semaphore();
int res;
uint32_t n = 0;
while ( 1 ) {
n += 1;
if ( !( n % 1000 ) ) {
res = sem_wait( sm );
if( res != 0 ) {
printf(" sem_wait %s. errno: %d\n", argv[2], errno);
}
printf( "Inst:%s RR Prio %s running (n=%u)\n", argv[2], argv[1], n );
fflush( stdout );
sem_post( sm );
sched_yield();
}
sched_yield();
}
sem_close( sm );
}
在子任务代码中,我有if ( !( n % 1000 ) ) 来试验减少等待和发布信号量时的争用/负载。我得到的结果是,当n % 1000 时,其中一个子进程将始终处于睡眠状态(来自top),而另一个子进程正常执行。但是,如果我设置n % 10000,即减少负载/争用,两个进程将运行并交错打印输出,这是我的预期结果。
有谁知道这是 semaphore.h 的限制还是有更好的方法来确保进程执行顺序?
【问题讨论】:
-
您的意思是设置调度策略和优先级,正如孩子在
main中的评论所暗示的那样?你的意思是在哪里设置这些?
标签: c++ linux pthreads semaphore taskscheduler