当前位置: 首页 > news >正文

阳西网站seoseo去哪里学

阳西网站seo,seo去哪里学,网站运营岗位职责描述,网站建设王滨1983目录 同步互斥的概念 互斥锁 初始化互斥锁 销毁互斥锁 申请上锁 解锁 案例1:没有互斥锁 多任务的运行情况 案例2:有互斥锁 多任务的运行情况 死锁 读写锁 初始化读写锁 销毁读写锁 申请读锁 申请写锁 释放读写锁 案例:两个任务…

目录

同步互斥的概念

互斥锁

初始化互斥锁

销毁互斥锁

申请上锁

解锁

案例1:没有互斥锁 多任务的运行情况

 案例2:有互斥锁 多任务的运行情况

死锁

读写锁

初始化读写锁

销毁读写锁

申请读锁

申请写锁

释放读写锁

案例:两个任务读 一个任务写

条件变量(重要)

概念引入

概念原理

 条件变量初始化

释放条件变量

等待条件

唤醒等待在条件变量上的线程

案例:生产者和消费者

信号量

信号量的API

初始化信号量

信号量减一 P操作

信号量加一 V操作

销毁信号量

使用场景

信号量用于线程的互斥

 信号量用于线程的同步

无名信号量 用于 血缘关系的进程间互斥

无名信号量 用于 血缘关系的进程间同步

有名信号量 用于 无血缘的进程间互斥

创建一个有名信号量

信号量的关闭

信号量文件的删除

案例:完成互斥

有名信号量 用于 无血缘的进程间同步


同步互斥的概念

互斥:同一时间,只能一个任务(进程或线程)执行,谁先运行不确定。

同步:同一时间,只能一个任务(进程或线程)执行,有顺序的运行。

同步 是特殊的 互斥。

互斥锁

用于线程的互斥。

互斥锁是一种简单的加锁的方法来控制对共享资源的访问,互斥锁只有两种状态,即加锁( lock )和解锁( unlock )

互斥锁的操作流程如下:

1)在访问共享资源临界区域前,对互斥锁进行加锁

2)在访问完成后释放互斥锁上的锁。 (解锁)

3)对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁 被释放。

互斥锁的数据类型是: pthread_mutex_t

初始化互斥锁

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

功能:

        初始化一个互斥锁。

参数:

        mutex:互斥锁地址。类型是 pthread_mutex_t 。

        attr:设置互斥量的属性,通常可采用默认属性,即可将 attr 设为 NULL。

        可以使用宏 PTHREAD_MUTEX_INITIALIZER 静态初始化互斥锁,比如:

        pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

        这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_mutex_init() 来完成动态初始

化,不同之处在于 PTHREAD_MUTEX_INITIALIZER 宏不进行错误检查

返回值:

        成功:0,成功申请的锁默认是打开的。

        失败:非 0 错误码

销毁互斥锁

#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);

功能:

        销毁指定的一个互斥锁。互斥锁在使用完毕后,必须要对互斥锁进行销毁,以释放资 源。

参数:

        mutex:互斥锁地址。

返回值:

        成功:0

        失败:非 0 错误码

申请上锁

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);

功能:

        对互斥锁上锁,若互斥锁已经上锁,则调用者阻塞,直到互斥锁解锁后再上锁。

参数:

        mutex:互斥锁地址。

返回值:

        成功:0

        失败:非 0 错误码

int pthread_mutex_trylock(pthread_mutex_t *mutex);

调用该函数时,若互斥锁未加锁,则上锁,返回 0;

若互斥锁已加锁,则函数直接返回失败,即 EBUSY。

解锁

#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);

功能:

        对指定的互斥锁解锁。

参数:

        mutex:互斥锁地址。

返回值:

        成功:0

        失败:非0错误码

案例1:没有互斥锁 多任务的运行情况

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>void *deal_fun01(void *arg)
{char *str = (char*)arg;while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}return NULL;
}void *deal_fun02(void *arg)
{char *str = (char*)arg;while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}return NULL;
}int main(int argc, char const *argv[])
{//创建两个线程pthread_t tid1,tid2;pthread_create(&tid1,NULL,deal_fun01,"hello");pthread_create(&tid2,NULL,deal_fun02,"world");pthread_detach(tid1);pthread_detach(tid2);return 0;
}

由于使用了pthread_detach,创建的线程还没来得及执行,进程就结束了,所以导致输出结果不全

使用pthread_join进行阻塞等待线程结束

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>void *deal_fun01(void *arg)
{char *str = (char*)arg;while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}return NULL;
}void *deal_fun02(void *arg)
{char *str = (char*)arg;while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}return NULL;
}int main(int argc, char const *argv[])
{//创建两个线程pthread_t tid1,tid2;pthread_create(&tid1,NULL,deal_fun01,"hello");pthread_create(&tid2,NULL,deal_fun02,"world");pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}

 案例2:有互斥锁 多任务的运行情况

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>//定义一把锁
pthread_mutex_t mutex;
void *deal_fun01(void *arg)
{char *str = (char*)arg;//上锁pthread_mutex_lock(&mutex);while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}//解锁pthread_mutex_unlock(&mutex);return NULL;
}void *deal_fun02(void *arg)
{char *str = (char*)arg;//上锁pthread_mutex_lock(&mutex);while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}//解锁pthread_mutex_unlock(&mutex);return NULL;
}int main(int argc, char const *argv[])
{//初始化锁pthread_mutex_init(&mutex,NULL);//创建两个线程pthread_t tid1,tid2;pthread_create(&tid1,NULL,deal_fun01,"hello");pthread_create(&tid2,NULL,deal_fun02,"world");pthread_join(tid1,NULL);pthread_join(tid2,NULL);//销毁锁pthread_mutex_destroy(&mutex);return 0;
}

 由于线程是相互独立的,所以线程处理函数可以合成一个函数

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>//定义一把锁
pthread_mutex_t mutex;
void *deal_fun(void *arg)
{char *str = (char*)arg;//上锁pthread_mutex_lock(&mutex);while(*str!='\0'){printf("%c",*str++);//没有换行符,需要强制刷新fflush(stdout);usleep(500000);}//解锁pthread_mutex_unlock(&mutex);return NULL;
}int main(int argc, char const *argv[])
{//初始化锁pthread_mutex_init(&mutex,NULL);//创建两个线程pthread_t tid1,tid2;pthread_create(&tid1,NULL,deal_fun,"hello");pthread_create(&tid2,NULL,deal_fun,"world");pthread_join(tid1,NULL);pthread_join(tid2,NULL);//销毁锁pthread_mutex_destroy(&mutex);return 0;
}

总结:

如果是互斥 不管有多少个任务,只需要一把锁,所有的任务上锁 访问资源 解锁

死锁

读写锁

POSIX 定义的读写锁的数据类型是: pthread_rwlock_t

初始化读写锁

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockattr_t *attr);

功能:

        用来初始化 rwlock 所指向的读写锁。

参数:

        rwlock:指向要初始化的读写锁指针。

        attr:读写锁的属性指针。如果 attr 为 NULL 则会使用默认的属性初始化读写锁,否则 使用指定的 attr 初始化读写锁。

        可以使用宏 PTHREAD_RWLOCK_INITIALIZER 静态初始化读写锁,比如:

        pthread_rwlock_t my_rwlock = PTHREAD_RWLOCK_INITIALIZER;

        这种方法等价于使用 NULL 指定的 attr 参数调用 pthread_rwlock_init() 来完成动态初 始化,不同之处在于PTHREAD_RWLOCK_INITIALIZER 宏不进行错误检查。

返回值:

        成功:0,读写锁的状态将成为已初始化和已解锁。

        失败:非 0 错误码。

销毁读写锁

#include <pthread.h>
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

功能:

        用于销毁一个读写锁,并释放所有相关联的资源(所谓的所有指的是由 pthread_rwlock_init() 自动申请的资源) 。

参数:

        rwlock:读写锁指针。

返回值:

        成功:0

        失败:非 0 错误码

申请读锁

#include <pthread.h>
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

功能:

        以阻塞方式在读写锁上获取读锁(读锁定)。

        如果没有写者持有该锁,并且没有写者阻塞在该锁上,则调用线程会获取读锁。

        如果调用线程未获取读锁,则它将阻塞直到它获取了该锁。一个线程可以在一个读写锁 上多次执行读锁定。

        线程可以成功调用 pthread_rwlock_rdlock() 函数 n 次,但是之后该线程必须调用

        pthread_rwlock_unlock() 函数 n 次才能解除锁定。

参数:

        rwlock:读写锁指针。

返回值:

        成功:0

        失败:非 0 错误码

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);

用于尝试以非阻塞的方式来在读写锁上获取读锁。

如果有任何的写者持有该锁或有写者阻塞在该读写锁上,则立即失败返回

申请写锁

#include <pthread.h>
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

功能:

        在读写锁上获取写锁(写锁定)。

        如果没有写者持有该锁,并且没有写者读者持有该锁,则调用线程会获取写锁。

        如果调用线程未获取写锁,则它将阻塞直到它获取了该锁。

参数:

        rwlock:读写锁指针。

返回值:

        成功:0

        失败:非 0 错误码

int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

用于尝试以非阻塞的方式来在读写锁上获取写锁。

如果有任何的读者或写者持有该锁,则立即失败返回。

释放读写锁

#include <pthread.h>
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

功能:

        无论是读锁或写锁,都可以通过此函数解锁。

参数:

        rwlock:读写锁指针。

返回值:

        成功:0

        失败:非 0 错误码

案例:两个任务读 一个任务写

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>//创建一把读写锁
pthread_rwlock_t rwlock;void *read_data01(void *arg)
{int *p=(int*)arg;while(1){//申请上读锁pthread_rwlock_rdlock(&rwlock);printf("任务A:num=%d\n",*p);//解读写锁pthread_rwlock_unlock(&rwlock);sleep(1);}return NULL;
}void *read_data02(void *arg)
{int *p=(int*)arg;while(1){//申请上读锁pthread_rwlock_rdlock(&rwlock);printf("任务B:num=%d\n",*p);//解读写锁pthread_rwlock_unlock(&rwlock);sleep(1);}return NULL;
}void *write_data(void *arg)
{int *p=(int*)arg;while(1){//申请上写锁pthread_rwlock_wrlock(&rwlock);(*p)++;//解读写锁pthread_rwlock_unlock(&rwlock);printf("任务C:写入num=%d\n",*p);sleep(2);}return NULL;
}int main(int argc, char const *argv[])
{//定义一个公共资源int num=0;//初始化读写锁pthread_rwlock_init(&rwlock,NULL);pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,read_data01,&num);pthread_create(&tid2,NULL,read_data02,&num);pthread_create(&tid3,NULL,write_data,&num);pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//销毁锁pthread_rwlock_destroy(&rwlock);return 0;
}

 

条件变量(重要)

概念引入

对于刚刚死锁的第三种情况。如果任务A先执行上锁,由于管道没有数据,所以读不到数据会一直阻塞,导致无法解锁;任务A无法解锁就会导致任务B无法上锁,也就无法向管道写入数据,同样会导致任务B阻塞等待上锁。

我们按照进程管道通信的方法,可以使用非阻塞读取来解决这个死锁问题。

但我们还可以通过条件变量来进行解决,任务A在执行到读数据的时候,发现管道里没有数据,就会通过条件变量临时解锁,从而通知任务B成功上锁进行数据写入。

概念原理

条件变量是用来等待条件满足而不是用来上锁的,条件变量本身不是锁。

条件变量和互斥锁同时使用。

条件变量的两个动作: 条件不满, 阻塞线程。当条件满足, 通知阻塞的线程开始工作。

条件变量的类型: pthread_cond_t。

原子操作: 几个操作连续进行,不可分割,不能被其它代码操作插入和打断。

 条件变量初始化

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond,
const pthread_condattr_t *attr);

功能:

        初始化一个条件变量

参数:

        cond:指向要初始化的条件变量指针。

        attr:条件变量属性,通常为默认值,传NULL即可 。

也可以使用静态初始化的方法,初始化条件变量:

        pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

返回值:

        成功:0

        失败:非0错误号

释放条件变量

#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);

功能:

        销毁一个条件变量

参数:

        cond:指向要初始化的条件变量指针

返回值:

        成功:0

        失败:非0错误号

等待条件

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex);

功能:

        阻塞等待一个条件变量

        如果阻塞就 先解锁、等待条件满足、重新上锁(3步为原子操作)解阻塞

参数:

        cond:指向要初始化的条件变量指针

        mutex:互斥锁

返回值:

        成功:0

        失败:非0错误号

int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,const struct *abstime);

功能:

        限时等待一个条件变量

参数:

        cond:指向要初始化的条件变量指针

        mutex:互斥锁

        abstime:绝对时间

返回值:

        成功:0

        失败:非0错误号

唤醒等待在条件变量上的线程

#include <pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);

功能:

        唤醒至少一个阻塞在条件变量上的线程

参数

        cond:指向要初始化的条件变量指

返回值

        成功:0

        失败:非0错误号

int pthread_cond_broadcast(pthread_cond_t *cond);

功能:

        唤醒全部阻塞在条件变量上的线程

参数:

        cond:指向要初始化的条件变量指针

返回值:

        成功:0

        失败:非0错误号

案例:生产者和消费者

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
//定义互斥锁
pthread_mutex_t mutex;
//定义条件变量
pthread_cond_t cond;
//定义一个仓库 默认有三个产品
int num = 3;void *comsumption_fun(void *arg) //消费
{while (1){//申请上锁pthread_mutex_lock(&mutex);//判断仓库是否为空 等待条件变量满足if (0 == num) //仓库为空{printf("%s 发现仓库为空,等待生产\n", (char *)arg);pthread_cond_wait(&cond, &mutex);}else{//进入仓库购买产品num--;printf("%s 购买了一个产品,仓库剩余%d个\n", (char *)arg, num);//使用产品printf("%s 正在使用产品\n", (char *)arg);}//解锁pthread_mutex_unlock(&mutex);sleep(rand() % 5);}
}void *production_fun(void *arg) //生产
{while (1){//生产一个产品sleep(rand() % 5);//上锁 进入仓库pthread_mutex_lock(&mutex);//将产品放入仓库num++;printf("%s 放入一个产品,仓库剩余%d\n", (char *)arg, num);//通知 条件变量阻塞的线程pthread_cond_broadcast(&cond);//解锁pthread_mutex_unlock(&mutex);}
}
int main(int argc, char const *argv[])
{//设计随机数种子srand(time(NULL));//初始化锁pthread_mutex_init(&mutex, NULL);//初始化条件变量pthread_cond_init(&cond, NULL);pthread_t tid1, tid2, tid3;pthread_create(&tid1, NULL, comsumption_fun, "消费者A");pthread_create(&tid2, NULL, comsumption_fun, "消费者B");pthread_create(&tid3, NULL, production_fun, "生产者");//等待线程结束pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);//销毁锁pthread_mutex_destroy(&mutex);//销毁条件变量pthread_cond_destroy(&cond);return 0;
}

信号量

信号量也叫信号灯,其本质就是一个计数器,描述临界资源的数目大小。(最多能有多少资源分配给线程)。

信号量可参考:信号量的概念 及其 操作函数(有名、无名信号量)_仲夏夜之梦~的博客-CSDN博客

前面的锁和条件变量只用于线程间同步互斥。而信号量广泛用于进程线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被 用来控制对公共资源的访问。

适用于六种情况:线程间的同步与互斥、有血缘进程间的同步与互斥、无血缘进程间的同步与互斥。

当信号量值大于 0 时,则可以访问,否则将阻塞

PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1

号量数据类型为:sem_t

信号量用于互斥

不管多少个任务互斥 只需要一个信号量(与前面的锁机制相同)。先P 任务 再 V

 

信号量用于同步

有多少个任务 就需要多少个信号量。最先执行的任务对应的信号量为1,其他信号量全 部为0。

每任务先P自己 任务 再V下一个任务的信号量

 

信号量的API

初始化信号量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value)

功能:

        创建一个信号量并初始化它的值。一个无名信号量在被使用前必须先初始化。

参数:

        sem:信号量的地址

        pshared:等于 0,信号量在线程间共享(常用);不等于0,信号量在进程间共享。

        value:信号量的初始值

返回值:

        成功:0

        失败: - 1

信号量减一 P操作

int sem_wait(sem_t *sem);

功能: 将信号量减一,如果信号量的值为0 则阻塞,大于0可以减一

参数:信号量的地址

返回值:成功返回0 失败返回-1

尝试对信号量减一

int sem_trywait(sem_t *sem);

功能: 尝试将信号量减一,如果信号量的值为0 不阻塞,立即返回 ,大于0可以减一

参数:信号量的地址

返回值:成功返回0 失败返回-1

信号量加一 V操作

int sem_post(sem_t *sem);

功能:将信号量加一

参数:信号量的地址

返回值:成功返回0 失败返回-1

销毁信号量

int sem_destroy(sem_t *sem);

功能: 销毁信号量

参数: 信号量的地址

返回值:成功返回0 失败返回-1

使用场景

信号量用于线程互斥

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>//定义一个信号量(用于互斥)
sem_t sem;void my_print(char* str)
{int i=0;while(str[i]!='\0'){printf("%c",str[i++]);fflush(stdout);sleep(1);}return;
}void *task_fun(void *arg)
{//P操作sem_wait(&sem);my_print((char*)arg);//V操作sem_post(&sem);return NULL;
}int main(int argc, char const *argv[])
{//信号量初始化为1sem_init(&sem,0,1);pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,task_fun,"hello");pthread_create(&tid2,NULL,task_fun,"world");pthread_create(&tid3,NULL,task_fun,"nanjing");pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//销毁信号量sem_destroy(&sem);return 0;
}

 信号量用于线程同步

#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>//定义一个信号量(用于互斥)
sem_t sem1,sem2,sem3;void my_print(char* str)
{int i=0;while(str[i]!='\0'){printf("%c",str[i++]);fflush(stdout);sleep(1);}return;
}void *task_fun01(void *arg)
{//P操作sem_wait(&sem2);my_print((char*)arg);//V操作sem_post(&sem3);return NULL;
}void *task_fun02(void *arg)
{//P操作sem_wait(&sem3);my_print((char*)arg);//V操作sem_post(&sem1);return NULL;
}void *task_fun03(void *arg)
{//P操作sem_wait(&sem1);my_print((char*)arg);//V操作sem_post(&sem2);return NULL;
}int main(int argc, char const *argv[])
{//信号量初始化为1sem_init(&sem1,0,1);sem_init(&sem2,0,0);sem_init(&sem3,0,0);pthread_t tid1,tid2,tid3;pthread_create(&tid1,NULL,task_fun01,"hello");pthread_create(&tid2,NULL,task_fun02,"world");pthread_create(&tid3,NULL,task_fun03,"nanjing");pthread_join(tid1,NULL);pthread_join(tid2,NULL);pthread_join(tid3,NULL);//销毁信号量sem_destroy(&sem1);sem_destroy(&sem2);sem_destroy(&sem3);return 0;
}

无名信号量 用于 血缘关系进程间互斥

如下图所示,通过一个普通的信号量想要实现父子进程间的互斥,由于父子进程使用的是独立的代码空间,因此当fork后,两个进程都会执行PV操作,因此这种方法无法实现进程互斥。

我们可以保证信号量是父子进程公共识别的,让信号量脱离父子进程空间。我们可以通过磁盘映射、存储映射、内存共享

#include <sys/mman.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/wait.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//定义一个无名信号量// MAP_ANONYMOUS匿名映射(不使用文件描述符),fd为-1表示不需要文件描述符sem_t *sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);//无名信号量的初始化    参数2:1表示进程sem_init(sem, 1, 1);pid_t pid = fork();if (pid == 0) //子进程{// P操作sem_wait(sem);my_print("hello");// V操作sem_post(sem);}else if (pid > 0) //父进程{// P操作sem_wait(sem);my_print("world");// V操作sem_post(sem);int status = 0;pid_t pid = wait(&status);}//销毁信号量sem_destroy(sem);
}

无名信号量 用于 血缘关系进程间同步

进程间的同步需要用到两个信号量

#include <sys/mman.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <sys/wait.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//定义一个无名信号量// MAP_ANONYMOUS匿名映射(不使用文件描述符),fd为-1表示不需要文件描述符sem_t *sem1 = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);sem_t *sem2 = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);//无名信号量的初始化    参数2:1表示进程sem_init(sem1, 1, 1);sem_init(sem2, 1, 0);pid_t pid = fork();if (pid == 0) //子进程{// P操作sem_wait(sem1);my_print("hello");// V操作sem_post(sem2);}else if (pid > 0) //父进程{// P操作sem_wait(sem2);my_print("world");// V操作sem_post(sem1);int status = 0;pid_t pid = wait(&status);}//销毁信号量sem_destroy(sem1);sem_destroy(sem2);
}

有名信号量 用于 无血缘进程间互斥

有名信号量的使用类似于文件操作,有名信号量创建完成之后,当前整个系统有效,直到系统重启或通过sem_unlink函数手动删除。

创建一个有名信号量

创建并初始化有名信号量或打开一个已存在的有名信号量。

注: 如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号量尚未存在时才初始化他。 如果所需的信号量已经存在,mode,value都会被忽略。

#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h>
//信号量存在
sem_t *sem_open(const char *name, int oflag);
//信号量不存在
sem_t *sem_open(const char *name, int oflag,
mode_t mode, unsigned int value);

功能:

        创建一个信号量

参数:

        name:信号量的名字

        oflag:sem_open函数的权限标志

        mode:文件权限(可读、可写、可执行 0777)的设置

        value:信号量的初始值

返回值:

        信号量的地址,失败:SEM_FAILED

信号量的关闭
int sem_close(sem_t *sem);

功能:关闭信号量

参数:信号量的的地址

返回值:成功0 失败-1

信号量文件的删除
#include <semaphore.h>
int sem_unlink(const char *name);

功能:删除信号量的文件

参数:信号量的文件名

返回值:成功0 失败-1

案例:完成互斥

TaskA.c

#include <stdio.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//创建一个有名信号量sem_open类似文件操作    最后一个参数为初始值sem_t *sem = sem_open("sem",O_RDWR|O_CREAT,0666,1);//P 操作sem_wait(sem);//任务my_print("hello world");//V 操作sem_post(sem);//关闭信号量sem_close(sem);//销毁信号量sem_destroy(sem);return 0;
}

TaskB.c

#include <stdio.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//创建一个有名信号量sem_open类似文件操作    最后一个参数为初始值sem_t *sem = sem_open("sem",O_RDWR|O_CREAT,0666,1);//P 操作sem_wait(sem);//任务my_print("nanjing 8.20");//V 操作sem_post(sem);//关闭信号量sem_close(sem);//销毁信号量sem_destroy(sem);return 0;
}

运行效果:先运行A,再运行B。A关闭有名信号量前,B无法打开有名信号量(阻塞)

有名信号量 用于 无血缘进程间同步

TaskA.c

#include <stdio.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//创建一个有名信号量sem_open类似文件操作    最后一个参数为初始值sem_t *sem1 = sem_open("sem1",O_RDWR|O_CREAT,0666,1);sem_t *sem2 = sem_open("sem2",O_RDWR|O_CREAT,0666,0);//P 操作sem_wait(sem1);//任务my_print("hello world");//V 操作sem_post(sem2);//关闭信号量sem_close(sem1);sem_close(sem2);//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
}

TaskB.c

#include <stdio.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>void my_print(char *str)
{int i = 0;while (str[i] != '\0'){printf("%c", str[i++]);fflush(stdout);sleep(1);}return;
}int main(int argc, char const *argv[])
{//创建一个有名信号量sem_open类似文件操作    最后一个参数为初始值sem_t *sem1 = sem_open("sem1",O_RDWR|O_CREAT,0666,1);sem_t *sem2 = sem_open("sem2",O_RDWR|O_CREAT,0666,0);//P 操作sem_wait(sem2);//任务my_print("nanjing 8.20");//V 操作sem_post(sem1);//关闭信号量sem_close(sem1);sem_close(sem2);//销毁信号量sem_destroy(sem1);sem_destroy(sem2);return 0;
}

http://www.hengruixuexiao.com/news/26668.html

相关文章:

  • 凤岗做网站廊坊关键词排名首页
  • 福田商城网站建设哪家便宜中国十大网站排名
  • 做加盟的网站建设毕业设计网站
  • 用c 做的网站怎么打开seo引擎优化是什么
  • 哪做网站比较好百度app下载链接
  • 网站建设客服接听术语百度小说风云榜2022
  • 怎么做消费信贷网站新余seo
  • 鹤壁做网站推广上海高玩seo
  • 南昌大学作风建设网站门户网站排行榜
  • 江苏 网站建设搜索引擎调词平台哪个好
  • 做教育行业网站seo案例
  • 北京东直门网站建设seo技术教程博客
  • 网站seo置顶 乐云践新专家企业推广文案
  • 武汉网站建设 网站制作腾讯nba新闻
  • 精利手表网站营销策划公司介绍
  • 做财务还是网站运营百度指数查询工具
  • 什么是网站链接优化网站设计的基本原则
  • 招聘网站可以同时做两份简历吗6郑州网站建设方案优化
  • 怎么样上传网站资料口碑营销的产品有哪些
  • 要做网站到哪里做软件外包公司有哪些
  • 做网站建设的销售薪水东莞网络营销代运营
  • 网站建设体会百度知道合伙人答题兼职
  • 织梦网站挂马教程sem优化是什么意思
  • 自己怎么做企业网站建设重庆做网络优化公司电话
  • 凡科建站公司专注于网站营销服务
  • 南宁百度网站建设公司哪家好seo搜索引擎优化服务
  • 网站空间管理信息电商运营培训课程有哪些
  • 南沙网站建设哪家好宣传方式
  • 网站怎么做地图导航seo具体怎么优化
  • 做网站推广优化靠谱seo关键词排名优化联系方式