Я пытаюсь узнать о семафорах и многопоточности. В примере, с которым я работаю, создаются потоки от 1 до t, причем каждый поток указывает на следующий, а последний — на первый поток. Эта программа позволяет каждому потоку последовательно проходить по очереди, пока все потоки не выполнят n ходов. Это когда программа заканчивается. Единственная проблема в функции tFunc, я занят, ожидая, когда наступит очередь конкретного потока. Я хочу знать, как использовать семафоры, чтобы все потоки засыпали и пробуждали поток только тогда, когда наступила его очередь, чтобы повысить эффективность.
int turn = 1;
int counter = 0;
int t, n;
struct tData {
int me;
int next;
};
void *tFunc(void *arg) {
struct tData *data;
data = (struct tData *) arg;
for (int i = 0; i < n; i++) {
while (turn != data->me) {
}
counter++;
turn = data->next;
}
}
int main (int argc, char *argv[]) {
t = atoi(argv[1]);
n = atoi(argv[2]);
struct tData td[t];
pthread_t threads[t];
int rc;
for (int i = 1; i <= t; i++) {
if (i == t) {
td[i].me = i;
td[i].next = 1;
}
else {
td[i].me = i;
td[i].next = i + 1;
}
rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
if (rc) {
cout << "Error: Unable to create thread, " << rc << endl;
exit(-1);
}
}
for (int i = 1; i <= t; i++) {
pthread_join(threads[i], NULL);
}
pthread_exit(NULL);
}
Использует мьютексы и условные переменные. Вот рабочий пример:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
int turn = 1;
int counter = 0;
int t, n;
struct tData {
int me;
int next;
};
pthread_mutex_t mutex;
pthread_cond_t cond;
void *tFunc(void *arg)
{
struct tData *data;
data = (struct tData *) arg;
pthread_mutex_lock(&mutex);
for (int i = 0; i < n; i++)
{
while (turn != data->me)
pthread_cond_wait(&cond, &mutex);
counter++;
turn = data->next;
printf("%d goes (turn %d of %d), %d next\n", data->me, i+1, n, turn);
pthread_cond_broadcast(&cond);
}
pthread_mutex_unlock(&mutex);
}
int main (int argc, char *argv[]) {
t = atoi(argv[1]);
n = atoi(argv[2]);
struct tData td[t + 1];
pthread_t threads[t + 1];
int rc;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
for (int i = 1; i <= t; i++)
{
td[i].me = i;
if (i == t)
td[i].next = 1;
else
td[i].next = i + 1;
rc = pthread_create(&threads[i], NULL, tFunc, (void *)&td[i]);
if (rc)
{
printf("Error: Unable to create thread: %d\n", rc);
exit(-1);
}
}
void *ret;
for (int i = 1; i <= t; i++)
pthread_join(threads[i], &ret);
}
использование N+1
семафоры. При запуске поток i
ждет на семафор i
, Когда проснулся, это «меняетand signals semaphore
я + 1`.
Основная нить порождает N
, темы, сигналы семафор 0 и ждет семафор N
,
Псевдокод:
sem s[N+1];
thread_proc (i):
repeat N:
wait (s [i])
do_work ()
signal (s [i+1])
main():
for i in 0 .. N:
spawn (thread_proc, i)
repeat N:
signal (s [0]);
wait (s [N]);
Имейте один семафор на поток. Есть каждая нить wait
на своем семафоре, повторная попытка, если sem_wait
возвращается EINTR
, Как только это сделано с его работой, имейте это post
на семафор следующего потока. Это позволяет избежать поведения «гремящего стада» решения Дэвида, пробуждая только один поток за раз.
Также обратите внимание, что, поскольку ваши семафоры никогда не будут иметь значения больше единицы, вы можете использовать pthread_mutex_t
за это.