使用 SysV 计数信号量
Counting semaphore using SysV
我想通过一个例子来理解计数信号量的概念。但是我想在 Linux.
中使用 SysV 来实现这个
我熟悉二进制信号量和计数信号量的理论部分。
我已经提到了这个link。
从概念上讲,信号量用作从一个进程到另一个进程的信号机制,所以我试图编写一个简单的程序。
在下面的程序中,我希望 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;
}
我是否必须使用多个信号量集才能实现我想要做的事情?
您需要两个计数为 1 的互斥量/信号量。
假设你的线程被称为 t0,t1,t2
并且你的信号量 sem0
和 sem1
,那么 t0
自由运行并递增 sem0
,t1
等待 sem0
并递增 sem1
,t2
等待 sem1
。
这是一个没有错误检查的完整草稿:
#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;
}
我 运行 线程顺序相反,在 t0
和 t1
之间等待 1 秒,t1
和 t2
到显示信号量执行从 t0
到 t2
.
排序线程的工作
@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;
}
顺便说一句,非常感谢您的解释。
我想通过一个例子来理解计数信号量的概念。但是我想在 Linux.
中使用 SysV 来实现这个
我熟悉二进制信号量和计数信号量的理论部分。
我已经提到了这个link。
从概念上讲,信号量用作从一个进程到另一个进程的信号机制,所以我试图编写一个简单的程序。
在下面的程序中,我希望 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;
}
我是否必须使用多个信号量集才能实现我想要做的事情?
您需要两个计数为 1 的互斥量/信号量。
假设你的线程被称为 t0,t1,t2
并且你的信号量 sem0
和 sem1
,那么 t0
自由运行并递增 sem0
,t1
等待 sem0
并递增 sem1
,t2
等待 sem1
。
这是一个没有错误检查的完整草稿:
#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;
}
我 运行 线程顺序相反,在 t0
和 t1
之间等待 1 秒,t1
和 t2
到显示信号量执行从 t0
到 t2
.
@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;
}
顺便说一句,非常感谢您的解释。