4、分析理解多线程执行中的互斥与同步
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<linux/sem.h>
#include<pthread.h>
int P(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
// 进行p操作
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "P failed\n");
return 0;
}
return 1;
}
int V(int sem_id) // 释放资源
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
// 进行v操作
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "V failed\n");
return 0;
}
return 1;
}
int n;
int product, empty;
void* eat(void* args)
{
while (1)
{
printf("儿子想吃水果\n");
sem_wait(&product);
sem_getvalue(&product, &n);
printf("儿子吃完水果了,现在有 %d 个水果\n", n);
sem_post(&empty);
sleep(1);
}
}
void* put_fruit(void* args)
{
while (1)
{
printf("主线程开始放水果\n");
sem_wait(&empty);
sleep(1);
sem_post(&product);
sem_getvalue(&product, &n);
printf("放入水果完成,现在有 %d 个水果 \n", n);
}
}
int main()
{
pthread_t threadP, threadC;
void* thread_result1,* thread_result2;
int semi, ret1, ret2;
semi = sem_init(&empty, 0, 5); //初始设置5个空资源,生产者可连续放入5次
if (semi == -1)
{
printf("empty非空,创建失败! \n");
return -1;
}
semi = sem_init(&product, 0, 0); //初始设置0个产品数
if (semi == -1)
{
printf("初始化失败! \n");
return -1;
}
ret1 = pthread_create(&threadC, NULL, eat, NULL);
ret2 = pthread_create(&threadP, NULL, put_fruit, NULL);
if (ret1 != 0 | ret2 != 0)
{
printf("线程创建失败! \n");
return -1;
}
ret1 = pthread_join(threadC, &thread_result1);
ret2 = pthread_join(threadP, &thread_result2);
if (ret1 != 0 || ret2 != 0)
{
perror("线程执行失败!\n");
exit(EXIT_FAILURE);
}
return 0;
}
分析:
一个线程进行放水果,一个线程吃水果。两者中product、empty作为信号量。其中讲吃水果的sleep时间分别设置1和10,比较了不同吃水果时间下的输出。
4、多线程编程实现一群生产者和一群消费者的生产和消费过程,使他们之间符合如下逻辑:没有产品不能消费,没有空不能放入
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<sys/shm.h>
#include<errno.h>
#include<fcntl.h>
#include<signal.h>
#define SIZE 1024
int e, f, m, m2;
char ch;
int in = 0, out = 0;
int inok = 0, outok = 0;
int shmin, shmout;
int* shminaddr, * shmoutaddr;
int waitsem(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "P failed\n");
return 0;
}
return 1;
}
int signalsem(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "V failed\n");
return 0;
}
return 1;
}
int main()
{
pid_t pid;
pid_t pids[20];
int i = 0;
shmin = shmget(IPC_PRIVATE, SIZE, IPC_CREAT | 0600);
shmout = shmget(IPC_PRIVATE, SIZE, IPC_CREAT | 0600);
shminaddr = 0;
shmoutaddr = 0;
e = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
f = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
m = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
m2 = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
semctl(e, 0, SETVAL, 10);
semctl(f, 0, SETVAL, 0);
semctl(m, 0, SETVAL, 1);
semctl(m2, 0, SETVAL, 1);
for (i = 0; i < 20; ++i)
{
pid = fork();
if (pid > 0)
{
pids[i] = pid;
}
if (pid == 0 && i % 2 == 0)
{
shminaddr = (int*)shmat(shmin, NULL, 0);
printf("PRODUCER %d is beginning\n", i / 2);
while (1)
{
waitsem(e);
waitsem(m);
printf("PRODUCER PUT OK,in=%d,IN=%d \n", in++, inok % 10);
sleep(rand() % 2);
signalsem(m);
signalsem(f);
}
}
if (pid == 0 && i % 2 == 1)
{
shmoutaddr = (int*)shmat(shmout, NULL, 0);
printf("CONSUMER %d is beginning \n", i / 2 + i % 2);
while (1)
{
waitsem(f);
waitsem(m2);
sleep(rand() % 6);
outok = (*shmoutaddr)++;
printf("CONSEMER PUT OK,out=%d,OUT=%d \n", out++, outok % 10);
signalsem(m2);
signalsem(e);
}
}
}
do
{
ch = getchar();
if (ch == 'q')
{
for (i = 0; i < 20; ++i)
{
kill(pids[i], SIGTERM);
}
}
} while (ch != 'q');
return 0;
}
分析:
多个生产者和多个消费者同时共享一个n大小的缓冲区,且缓冲区一次只能允许一个进程使用。
生产者对e申请后才能向下执行,放入产品后会释放f信号,消费者相反。