Если задача именно такая, как сформулирована в тексте вопроса (не в заголовке), а именно -- параллельно выполнить операцию A в N потоках, а после их завершения выполнить B, то никакие семафоры/мьютексы для ее синхронизации не нужны.
Псевдокод:
pthread_t tid[N];
void *arg[N]; // аргументы для каждой A
void *res[N]; // результаты каждой A
for (int i = 0; i <N; i++)
tid[i] = pthread_create(tid + i, 0, A, arg[i]);
for (int i = 0; i <N; i++)
pthread_join(tid[i], res[i]);
B();
Достаточно просто дождаться завершения N потоков, а потом выполнить B().
Update
Я понял, что вас интересует более общий случай. Синхронизировать количество потоков каждого вида (A и B) можно используя pthread_mutex вместе с pthread_cond.
Безусловно, то же можно сделать, используя вместо pthread.h semaphore.h (см. man semaphore.h), но я сейчас лучше помню работу с мьютексами.
Вот, набросал игрушку, котрая иллюстрирует работающий подход
avp@avp-xub11:hashcode$ cat cp.c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#define N 3
volatile int Acnt = 0, Bcnt = 0, Alim = N;
pthread_mutex_t lock;
pthread_cond_t cond;
void *thA (void *a) {
int i = (long)a;
pthread_mutex_lock(&lock);
printf("A:%d start (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
while (Acnt + 1 > Alim)
pthread_cond_wait(&cond, &lock);
Acnt++;
printf("A:%d run (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
pthread_mutex_unlock(&lock);
// work
usleep(rand() % 1000000);
pthread_mutex_lock(&lock);
Acnt--;
printf("A:%d stop (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
void *thB (void *a) {
int i = (long)a;
pthread_mutex_lock(&lock);
printf("B:%d start (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
while (Acnt > 0 || Bcnt > 0)
pthread_cond_wait(&cond, &lock);
Bcnt++;
printf("B:%d run (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
pthread_mutex_unlock(&lock);
// work
usleep(rand() % 1000000);
pthread_mutex_lock(&lock);
Bcnt--;
printf("B:%d stop (%d A %d B Alim: %d)\n", i, Acnt, Bcnt, Alim);
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&lock);
}
pthread_t runA (int i) {
pthread_t r;
return pthread_create(&r, 0, thA, (void *)(long)i), r;
}
pthread_t runB (int i) {
pthread_t r;
return pthread_create(&r, 0, thB, (void *)(long)i), r;
}
int
main (int ac, char *av[])
{
pthread_mutex_init(&lock, 0);
pthread_cond_init(&cond, 0);
pthread_t all[10000];
int c, i, n = 0;
while ((c = getchar()) != EOF) {
if (isdigit(c))
Alim = c - '0' + 1;
else
all[n++] = (c == 'a')? runA(n) : runB(n);
usleep(100);
}
for (i = 0; i < n; i++)
printf ("thread %d join %d\n", i + 1, pthread_join(all[i], 0));
return puts("End") == EOF;
}
avp@avp-xub11:hashcode$ gcc cp.c -pthread
avp@avp-xub11:hashcode$ ./a.out
baa
B:1 start (0 A 0 B Alim: 3)
B:1 run (0 A 1 B Alim: 3)
A:3 start (0 A 1 B Alim: 3)
A:3 run (1 A 1 B Alim: 3)
A:2 start (1 A 1 B Alim: 3)
A:2 run (2 A 1 B Alim: 3)
B:4 start (2 A 1 B Alim: 3)
B:1 stop (2 A 0 B Alim: 3)
A:2 stop (1 A 0 B Alim: 3)
A:3 stop (0 A 0 B Alim: 3)
B:4 run (0 A 1 B Alim: 3)
B:4 stop (0 A 0 B Alim: 3)
baaab
B:5 start (0 A 0 B Alim: 3)
B:5 run (0 A 1 B Alim: 3)
A:6 start (0 A 1 B Alim: 3)
A:6 run (1 A 1 B Alim: 3)
A:7 start (1 A 1 B Alim: 3)
A:7 run (2 A 1 B Alim: 3)
A:8 start (2 A 1 B Alim: 3)
A:8 run (3 A 1 B Alim: 3)
B:9 start (3 A 1 B Alim: 3)
B:10 start (3 A 1 B Alim: 3)
A:6 stop (2 A 1 B Alim: 3)
B:5 stop (2 A 0 B Alim: 3)
A:8 stop (1 A 0 B Alim: 3)
A:7 stop (0 A 0 B Alim: 3)
B:9 run (0 A 1 B Alim: 3)
B:9 stop (0 A 0 B Alim: 3)
B:10 run (0 A 1 B Alim: 3)
B:10 stop (0 A 0 B Alim: 3)
thread 1 join 0
thread 2 join 0
thread 3 join 0
thread 4 join 0
thread 5 join 0
thread 6 join 0
thread 7 join 0
thread 8 join 0
thread 9 join 0
thread 10 join 0
End
avp@avp-xub11:hashcode$
Как работают pthread_cond_wait и pthread_cond_broadcast (именно на них построена синхронизация в этой программке) почитайте в man
.
Если вопросы останутся -- задавайте.