目录
1、代码
注:以下代码在windows子系统的ubuntu运行结果不及预期,SCHED_FIFO设置返回成功,但是实际并没有生效,不知为何,请知道原因的小伙伴不吝赐教,感谢!所以代码是运行在云服务器的unbuntu系统,结果符合预期。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#define _GNU_SOURCE
#include <pthread.h>
#include <errno.h>
#include <sched.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <semaphore.h>
#define SIZE 1023
#define KEY ((key_t)0x5005)
#define THREAD1 0
#define THREAD2 1
sem_t g_sem;
sem_t g_thread_ind[2];
int create_thread(pthread_t* thread_id, int detach_state, int schedpolicy, int priority, int inherit_sched,
int scope, char* thread_name, void* (*func)(void*), void* arg);
void* thread1_main_func(void* arg);
void* thread2_main_func(void* arg);
int main()
{
sem_init(&g_sem, 0, 0);
sem_init(&g_thread_ind[THREAD1], 0, 1);
sem_init(&g_thread_ind[THREAD2], 0, 1);
int ret = 0;
struct rlimit rlim;
ret = getrlimit(RLIMIT_RTPRIO, &rlim);
if(ret != 0)
{
printf("error %d for getrlimit\n", errno);
}
else
{
printf("rlim cur %ld, rlimit max %ld\n", rlim.rlim_cur, rlim.rlim_max);
}
ret = getrlimit(RLIMIT_RTTIME, &rlim);
if(ret != 0)
{
printf("error %d for getrlimit\n", errno);
}
else
{
printf("rlim cur %ld, rlimit max %ld\n", rlim.rlim_cur, rlim.rlim_max);
}
pthread_t thread1;
pthread_t thread2;
int shmId;
struct sched_param sp = {0};
sp.sched_priority = 0;
ret = sched_setscheduler(getpid(), SCHED_OTHER, &sp);
if (0 != ret) printf("set sched policy failed!, errno %d\n", errno);
else printf("get sched policy : %d, SCHED_FIFO = %d, SCHED_OTHER = %d, max pri: %d\n",
sched_getscheduler(getpid()), SCHED_FIFO, SCHED_OTHER, sched_get_priority_max(SCHED_FIFO));
shmId = shmget(KEY, SIZE, IPC_CREAT | 0666);
if (shmId < 0)
{
perror("get shm ipc id error");
return -1;
}
printf("shmid %d\n", shmId);
ret = create_thread(&thread1, PTHREAD_CREATE_DETACHED, SCHED_OTHER, 0, PTHREAD_EXPLICIT_SCHED,
PTHREAD_SCOPE_SYSTEM, "THREAD1", thread1_main_func, (void*)((long)shmId));
if (ret != 0)
{
printf("create thread failed, errno %d\n", errno);
return -1;
}
ret = create_thread(&thread2, PTHREAD_CREATE_DETACHED, SCHED_FIFO, 99, PTHREAD_EXPLICIT_SCHED,
PTHREAD_SCOPE_SYSTEM, "THREAD2", thread2_main_func, (void*)((long)shmId));
if (ret != 0)
{
printf("create thread failed, errno %d\n", errno);
return -1;
}
int loop = 200;
printf("policy %d \n", sched_getscheduler(0));
while(1)
{
printf("main func start\n");
for (int loop = 0; loop < 1000000000; loop++);
sem_post(&g_thread_ind[THREAD1]);
sem_post(&g_thread_ind[THREAD2]);
printf("main func end\n");
}
return 0;
}
int create_thread(pthread_t* thread_id, int detach_state, int schedpolicy, int priority, int inherit_sched,
int scope, char* thread_name, void* (*func)(void*), void* arg)
{
int rc = 0;
pthread_attr_t thread_attr;
rc = pthread_attr_init(&thread_attr);
if (0 == rc && detach_state != PTHREAD_CREATE_JOINABLE)
{
rc = pthread_attr_setdetachstate(&thread_attr, detach_state);
}
if (0 == rc && schedpolicy != SCHED_OTHER)
{
rc = pthread_attr_setschedpolicy(&thread_attr, schedpolicy);
}
if (0 == rc && priority != 0)
{
struct sched_param schedparam = {0};
schedparam.sched_priority = priority;
rc = pthread_attr_setschedparam(&thread_attr, &schedparam);
}
if (0 == rc && inherit_sched != PTHREAD_INHERIT_SCHED)
{
rc = pthread_attr_setinheritsched(&thread_attr, inherit_sched);
}
if (0 ==rc && scope != PTHREAD_SCOPE_SYSTEM)
{
rc = pthread_attr_setscope(&thread_attr, scope);
}
if (0 != rc) return rc;
else rc = pthread_create(thread_id, &thread_attr, func, arg);
if (0 != rc) return rc;
else return (pthread_setname_np(*thread_id, (const char*)thread_name));
}
void* thread1_main_func(void* arg)
{
struct sched_param sp = {0};
sp.sched_priority = 98;
sched_setscheduler(syscall(SYS_gettid), SCHED_FIFO, &sp);
int exist_shmid = shmget(KEY, 0, 0666 | IPC_CREAT);
char* shmaddr = NULL;
int shmid = (int)((long)arg);
printf("thread1: shmid %d, exist_shmid %d\n", shmid, exist_shmid);
shmaddr = (char*)shmat(shmid, NULL, 0);
if (shmaddr == (char*)-1)
{
perror("shmat addr error");
//pthread_exit(0);
}
strcpy(shmaddr, "hi, i am thread1\n");
printf("thread1 write: %s", shmaddr);
printf("thread1 policy %d \n", sched_getscheduler(syscall(SYS_gettid)));
sem_post(&g_sem);
shmdt(shmaddr);
while(1)
{
sem_wait(&g_thread_ind[THREAD1]);
printf("thread1 loop start\n");
for (int loop = 0; loop < 1000000000; loop++);
printf("thread1 loop end\n");
}
pthread_exit(0);
}
void* thread2_main_func(void* arg)
{
char* shmaddr = NULL;
int shmid = (int)((long)arg);
printf("thread2 \n");
sem_wait(&g_sem);
printf("thread2 : shmid %d\n", shmid);
shmaddr = (char*)shmat(shmid, NULL, 0);
if (shmaddr == (char*)-1)
{
perror("shmat addr error");
//pthread_exit(0);
}
printf("thread2 read: %s", shmaddr);
printf("thread2 policy %d \n", sched_getscheduler(syscall(SYS_gettid)));
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, 0);
sem_destroy(&g_sem);
while(1)
{
sem_wait(&g_thread_ind[THREAD2]);
printf("thread2 loop start\n");
for (int loop = 0; loop < 1000000000; loop++);
printf("thread2 loop end\n");
}
pthread_exit(0);
}
运行结果:
主进程设置默认的SCHED_OTHER普通调度策略,并没有设置NICE值。
线程1的调度策略为SCHED_FIFO,优先级98,线程2的调度策略为SCHED_FIFO,优先级99。
如果不使用信号量g_thread_ind,那么线程2将一直循环执行,不过主进程的调度策略为普通调度策略,所以linux会分一点cpu时间给主进程来运行,但是线程1将不会得到调度。因为跑的服务器只有一个cpu,所以也无法为线程1绑定其他的cpu来运行。
于是乎,使用信号量g_thread_ind可以解决这个问题,让线程2阻塞等待信号量,这样线程1就可以执行了。
还有一个需要说明下,线程1和线程2的执行顺序是固定的,说明信号量有优先级唤醒问题,线程2的优先级更高,所以先运行。
top -H -p pid命令查看线程调度策略实现结果: