2017-04-21 63 views
1

我想通过一个例子来理解计数信号量的概念。但我想在Linux中使用SysV来实现这一点。
我熟悉二进制信号量的理论部分和计数信号量。
我已经提到这个link使用SysV计数信号量

从概念上讲,信号量被用作从一个进程到另一个进程的信号机制,所以我试图编写一个简单的程序。

在下面的节目,我想thread_1等到它不会从thread_2得到一个信号,同样thread_2应该等到它不会从thread_3得到的信号。

从而使输出应该是这样的: Hello From thread 3 Hello from thread 2 Hello from thread 1

我知道它可以使用pthread_join()正常进行,但我想用信号量来实现它。

代码:

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <errno.h> 

int sem_id; 
struct sembuf sops[3]; 
void thread_1(void) 
{ 
    sops[0].sem_num = 0; 
    sops[0].sem_op = 0; 
    sops[0].sem_flg = 0; 

    if(semop(sem_id, sops, 1) < 0) 
     perror("Semop In thread 3"); 
    else 
     printf("Hello From thread 1\n"); 
} 

void thread_2(void) 
{ 
    sops[0].sem_num = 0; 
    sops[0].sem_op = -1; 
    sops[0].sem_flg = 0; 

    if(semop(sem_id, sops, 1) < 0) 
     perror("Semop In thread 2"); 
    else 
     printf("Hello from thread 2\n"); 
} 

void thread_3(void) 
{ 

    sops[0].sem_num = 0; 
    sops[0].sem_op = -1; 
    sops[0].sem_flg = 0; 

    if(semop(sem_id, sops, 1) < 0) 
     perror("Semop In thread 3"); 
    else 
     printf("Hello from thread 3\n"); 
} 

int main(void) 
{ 
    void (*funct[]) = {thread_1, thread_2, thread_3}; 

    key_t semkey; 
    char i; 
    union semun { 
       int    val; /* Value for SETVAL */ 
       struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 
       unsigned short *array; /* Array for GETALL, SETALL */ 
       struct seminfo *__buf; /* Buffer for IPC_INFO 
              (Linux-specific) */ 
      }arg; 
    pthread_t thread_id[3]; 

    semkey = ftok("/tmp", 'a'); 

    if(semkey < 0) 
     perror("Cannot Create Semaphore Key"); 
    else 
    { 
     sem_id = semget(semkey, 1, (IPC_CREAT|IPC_EXCL|0666)); 
     if(sem_id < 0) 
      perror("Cannot create semaphore\n"); 
     else 
     { 
      arg.val = 3; 
      if (semctl(sem_id, 0, SETVAL, arg) == -1) { 
       perror("semctl"); 
       exit(1); 
      } 
     } 
    } 

    for(i = 0; i < 3; i++) 
    { 
     if(pthread_create(&thread_id[i], NULL, funct[i], NULL) < 0) 
      perror("Cannot Create thread\n"); 
    } 

    for(i = 0; i < 3; i++) 
     pthread_join(thread_id[i], NULL); 

    if(semctl(sem_id, 0, IPC_RMID, NULL) == -1) 
     perror("semctl"); 

    return 0; 
} 

我必须使用一个以上的信号设置要达到什么,我试图做的?

+0

没有pthread_wait,顺便说一句。你可能是指pthread_join。 – PSkocik

+0

是的,谢谢。修正完成! – Gaurav

回答

1

您需要使用计数1 2个互斥/信号灯假设你的主题被称为t0,t1,t2和你的信号灯sem0sem1,然后t0自由奔跑和增量sem0,在sem0和增量sem1t1等待,并在sem1t2等待。

这里是没有错误检查的完整草案:

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <errno.h> 

static int sem0, sem1; 
#define POST1(Sem) semop(Sem, &(struct sembuf){0,1,0}, 1) 
#define WAIT1(Sem) semop(Sem, &(struct sembuf){0,-1,0}, 1) 

static void* t0(void *unused) { puts("hello from t0"); POST1(sem0); return 0; } 
static void* t1(void *unused) { WAIT1(sem0); puts("hello from t1"); POST1(sem1); return 0; } 
static void* t2(void *unused) { WAIT1(sem1); puts("hello from t2"); return 0; } 

int main(void) 
{ 
    key_t sem0_k, sem1_k; 
    sem0_k = ftok("/tmp", '0'); 
    sem1_k = ftok("/tmp", '1'); 

    sem0 = semget(sem0_k, 1, (IPC_CREAT|IPC_EXCL|0666)); 
    sem1 = semget(sem1_k, 1, (IPC_CREAT|IPC_EXCL|0666)); 

    pthread_t tids[3]; 
    pthread_create(tids+2, NULL, t2, NULL); 
    sleep(1); 
    pthread_create(tids+1, NULL, t1, NULL); 
    sleep(1); 
    pthread_create(tids+0, NULL, t0, NULL); 

    for(int i = 0; i < 3; i++) 
     pthread_join(tids[i], NULL); 

    semctl(sem0, 0, IPC_RMID, NULL); 
    semctl(sem1, 0, IPC_RMID, NULL); 

    return 0; 
} 

我正在以相反的顺序,并与t0t1,并t1t2之间1秒等待显示信号量做的工作线程订购从t0t2的线程。

+0

非常感谢您的解释。 – Gaurav

1

@PSkocik,基于你的回答,我修改了我的代码以使用一组两个信号量。这里是代码:

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <sys/types.h> 
#include <sys/ipc.h> 
#include <sys/sem.h> 
#include <errno.h> 

int sem_id; 

struct sembuf sops; 
void thread_1(void) 
{ 
    /*Wait on Set1 of Semaphore*/ 
    sops.sem_num = 1; 
    sops.sem_op = -1; 
    sops.sem_flg = 0; 

    if(semop(sem_id, &sops, 1) < 0) 
     perror("Semop Wait In thread 3"); 
    else 
     printf("Hello From thread 1\n"); 
} 


void thread_2(void) 
{ 
    /*Wait on Set0 of Semaphore*/ 
    sops.sem_num = 0; 
    sops.sem_op = -1; 
    sops.sem_flg = 0; 

    if(semop(sem_id, &sops, 1) < 0) 
     perror("Semop Wait In thread 2"); 
    else 
     printf("Hello from thread 2\n"); 

    /*Post on Set1 of Semaphore*/   
    sops.sem_num = 1; 
    sops.sem_op = 1; 
    sops.sem_flg = 0; 

    if(semop(sem_id, &sops, 1) < 0) 
     perror("Semop Post In thread 2"); 
} 

void thread_3(void) 
{ 
    printf("Hello from thread 3\n"); 

    /*Post operation on Set0 of semaphore*/ 
    sops.sem_num = 0; 
    sops.sem_op = 1; 
    sops.sem_flg = 0; 

    if(semop(sem_id, &sops, 1) < 0) 
     perror("Semop In thread 3"); 
    else 
    { ; } 
} 

int main(void) 
{ 
    void (*funct[]) = {thread_1, thread_2, thread_3}; 

    key_t semkey; 
    char i; 
    union semun { 
       int    val; /* Value for SETVAL */ 
       struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */ 
       unsigned short *array; /* Array for GETALL, SETALL */ 
       struct seminfo *__buf; /* Buffer for IPC_INFO 
              (Linux-specific) */ 
      }arg; 
    pthread_t thread_id[3]; 

    semkey = ftok("/tmp", 'a'); 

    if(semkey < 0) 
     perror("Cannot Create Semaphore Key"); 
    else 
    { 
     sem_id = semget(semkey, 2, (IPC_CREAT|IPC_EXCL|0666)); 
     if(sem_id < 0) 
      perror("Cannot create semaphore\n"); 
     else 
     { 
      /*arg.val = 3; 
      if (semctl(sem_id, 0, SETVAL, arg) == -1) { 
       perror("semctl"); 
       exit(1); 
      }*/ 
     } 
    } 

    for(i = 0; i < 3; i++) 
    { 
     if(pthread_create(&thread_id[i], NULL, funct[i], NULL) < 0) 
      perror("Cannot Create thread\n"); 
    } 

    for(i = 0; i < 3; i++) 
     pthread_join(thread_id[i], NULL); 

    if(semctl(sem_id, 0, IPC_RMID, NULL) == -1) 
     perror("semctl"); 

    return 0; 
} 

顺便说一句,感谢一堆为您的解释。

+0

是的。使用SysV信号量比单个信号量的两个独立信号量集更好(尽管如果问题并不比这更复杂,那么应该使用pthread互斥锁或posix信号量,因为与sysv信号量相比,这些信号量要轻得多)。 – PSkocik

+0

是的,我研究过SysV信号量在内核级别运行的地方,但是不太确定。 – Gaurav