Linuxカーネル4.4.0-57でC++ 11を使用して、2つのビジーループプロセス(例:p1、p2)を固定しようとしています(pthread_setaffinity_np )を同じコアに置き、POSIXセマフォ(セマフォーh)とsched_yield()を使用してインターリーブの実行順序を確認します。しかし、うまくいきませんでした。POSIXセマフォが高競合/負荷の下で動作しない
以下は、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
の場合、子プロセスの1つが常にスリープ状態(からまで)になり、他の子プロセスが正しく実行されるということです。しかし、n % 10000
を設定すると負荷/競合が少なくなり、両方のプロセスが実行され、インターリーブ出力が出力されますが、これは私の予想される結果です。
これがsemaphore.hの制限であるかどうかは誰にも分かりませんが、プロセスの実行順序を確実にする良い方法がありますか?
「main」の子供のコメントが示唆するように、スケジューリングポリシーと優先度を設定することを意味しますか?それらを設定するのはどこですか? – pilcrow