2016-10-24 4 views
2

Я хотел бы реализовать многопотоковый процесс, который отвечает за запуск потоков параллельно.Процесс многопоточности C с непредвиденным сбоем процессора

Согласно выводам htop, каждая нить потребляет менее 1% процессора, но основная потребляет около 100% процессора.

int main (int argc, char *argv[]) 
{ 
    struct sigaction action; 
    int i; 
    exitReq = 0; 
    memset(&engine, 0, sizeof(stEngine_t)); 
    engine.NbTasks = 12; 

    engine.TaskThread = malloc(engine.NbTasks * sizeof(stTask_t)); 

    /* NbTasks = 12 */ 
    for (i = 0; i < engine.NbTasks; i++) { 
     engine.TaskThread[i] = array[i]; 
     engine.TaskThread[i].initTask(); 
     pthread_create(&engine.TaskThread[i].tId, NULL, my_handler, (void *) &engine.TaskThread[i]); 
    } 

    while (!exitReq) { 
     //.. do stuff as reading external value (if value < limit => exitReq = 1) 
     sched_yield(); 
    } 

    for (i = 0; i < engine.NbTasks; i++) { 
     (void)pthread_cancel(engine.TaskThread[i].tId); 
     pthread_join(engine.TaskThread[i].tId, NULL); 
     engine.TaskThread[i].stopTask(); 
     engine.TaskThread[i].tId = 0; 
    } 
    free(engine.TaskThread); 
    memset(&engine, 0, sizeof(stEngine_t));   
    return 0; 
} 

static void* my_handler(void* params) 
{ 
    stTask_t* ptask = (stTask_t*) params; 

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 

    while (!exitReq) { 
     ptask->launchTask(); 
     pthread_testcancel(); 
    } 
    pthread_exit(NULL); 
} 

Людей страницы sched_yield говорит «sched_yield() приводит к тому, вызывающему потоку отказываться от процессора.», Поэтому он был использован внутри цикла.

Я, вероятно, неправильно понял что-то о функции sched_yield(), но есть ли лучший и надежный способ отказаться от CPU в этой конкретной ситуации.

+1

Это все еще занятый цикл, почему бы ему не использовать весь процессор, если никто его не хочет? –

+0

Действительно, цикл работает, но его задача не должна потреблять весь процессор. Это то, что я хочу понять и улучшить. – ogs

+2

OT: одновременный доступ к 'exitReq' должен быть защищен, например, мьютексом. – alk

ответ

4

sched_yield() не помещает ваш поток в спящий режим. Он просто отталкивает его до конца очереди потоков, которая должна выполняться процессором. Тем не менее, ваш поток по-прежнему является работает поток, и будет запущен снова, как только в очереди нет других потоков.

Что происходит, если ваш поток работает только в очереди, он будет перенесен немедленно каждый раз, используя 100% CPU.

Возможно, вы хотите, чтобы положить нить спать, либо позвонив по телефону спать прямо, или блок-ожидании какого-либо события (например, poll())

+0

, но в очереди осталось еще 12 оставшихся бегущих потоков. – Domso

+1

@Domso Мы не можем видеть, что они делают (я не вижу код для того, что указывает 'launchTask()'). Возможно, они занимают некоторое процессорное время, или, может быть, нет (OP предлагает 1%, поэтому не так много), что говорит Луис, так это то, что Main loop/thread будет поднимать любой запасной процессор. –

+0

@code_fodde Я согласен, но я думаю, что остальные 12 потоков действительно не работают постоянно. Мы не знаем этого наверняка, но если функция не использует какие-либо ресурсы при выполнении внутри цикла, функция также должна содержать некоторое ожидание. Однако, 'launchTask()' должно быть выполнено – Domso

2

Я считаю, что другой взять на себя в том, что sched_yield(); в основном такая же, как Sleep(0); , Где:

Нулевое значение вызывает нить отказываться от оставшейся части своего квант времени в любой другой поток, который готов к запуску. Если нет других потоков, готовых к запуску, функция немедленно возвращается, а поток продолжает выполнение.

(ок, да это из MSDN - но он объясняет это достаточно хорошо)

Довольно много, как Luis de Arquer упоминает (+1 там). Но обычно это не оптимальный подход, т. Е. Обычно это «бит взлома», чтобы заставить ОС выполнять свою работу по своему усмотрению.

Не то, что это, вероятно, действительно имеет много, и я делал это много в прошлом для маленьких приложений ... но вы можете попробовать использовать pthread_cond_wait(); сделать ожидание и pthread_cond_broadcast() или pthread_cond_signal() просыпаться, с - или с таким количеством потоки, может быть, семафор - где каждый поток сигнализирует, когда он завершен, поэтому основное может продолжаться ... здесь у вас есть несколько вариантов.

+1

На самом деле, интересно, есть ли подходящий вариант использования для 'sched_yield()' или 'Sleep (0)', где они действительно полезны (в пользовательском пространстве). –

+0

lol ... хороший вопрос, ermmm, я на самом деле использую его довольно много, когда я ленив, или просто не забочусь о небольшом ударе по производительности (или чаще обычно спящий (1)/sleep (1) - обычно в небольшие проекты или тестовые приложения. Но ваш вопрос интересен ... возможно, стоит опубликовать его в качестве вопроса! –

+0

Нашел [это] (http://stackoverflow.com/a/24999481/7033248) на поток java, так что, вероятно, это будет помечено как дублирующее. Но я не слишком уверен, что это хороший подход ... Несколько потоков, работающих на одни и те же байты в больших масштабах, разве это не ужасно для кеша? –

Смежные вопросы