一.哪些是讯号量

讯号量的使用主要是拿来保护共享资源,致使资源在一个时刻只有一个进程(线程)

所拥有。

讯号量的值为正的时侯,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明

它被占用,测试的线程要步入睡眠队列中,等待被唤起。

二.讯号量的分类

在学习讯号量之前,我们必须先晓得——Linux提供两种讯号量:

(1)内核讯号量,由内核控制路径使用

(2)用户态进程使用的讯号量,这些讯号量又分为POSIX讯号量和SYSTEMV讯号量。POSIX讯号量又分为有名讯号量和无名讯号量。

有名讯号量,其值保存在文件中,所以它可以用于线程也可以用于进程间的同步。无名讯号量,其值保存在显存中。

如果对讯号量没有以上的全面认识的话,你都会很快发觉自己在讯号量的森林里迷失了方向。

三.内核讯号量

1.内核讯号量的构成

内核讯号量类似于载流子锁,由于当锁关掉着时,它不容许内核控制路径继续进行。但是,当内核控制路径企图获取内核讯号量锁保护的忙资源时,相应的进程就被挂起。只有在资源被释放时,进程才再度变为可运行。

只有可以睡眠的函数能够获取内核讯号量;中断处理程序和可延后函数都不能使用内核讯号量。

内核讯号量是structsemaphore类型的对象,它在中定义:

structsemaphore{

atomic_tcount;

intsleepers;

wait_queue_head_twait;

count:相当于讯号量的值,小于0,资源空闲;等于0,资源忙,但没有进程等待这

个保护的资源;大于0,资源不可用,并起码有一个进程等待资源。

wait:储存等待队列数组的地址,当前等待资源的所有睡眠进程就会置于这个数组中。

sleepers:储存一个标志,表示是否有一些进程在讯号量上睡眠。

2.内核讯号量中的等待队列(删掉,没有联系)

里面早已提及了内核讯号量使用了等待队列wait_queue来实现阻塞操作。

当某任务因为没有某种条件没有得到满足时,它就被挂到等待队列中睡眠。当条件得到满足时,该任务就被移出等待队列,此时并不意味着该任务就被马上执行,由于它又被移进工作队列中等待CPU资源,在适当的时机被调度。

内核讯号量是在内部使用等待队列的,也就是说该等待队列对用户是隐藏的,无须用户干涉。由用户真正使用的等待队列我们将在另外的篇章进行解读。

3.内核讯号量的相关函数

(1)初始化:

voidsema_init(structsemaphore*sem,intval);

voidinit_MUTEX(structsemaphore*sem);//将sem的值置为1,表示资源空闲

linux多进程信号量_进程间通信信号量_linux 进程通信 信号量

voidinit_MUTEX_LOCKED(structsemaphore*sem);//将sem的值置为0,表示资源忙

(2)申请内核讯号量所保护的资源:

voiddown(structsemaphore*sem);//可导致睡眠

intdown_interruptible(structsemaphore*sem);//down_interruptible能被讯号打断

intdown_trylock(structsemaphore*sem);//非阻塞函数,不会睡眠。未能锁定资源则马上返回

(3)释放内核讯号量所保护的资源:

voidup(structsemaphore*sem);

4.内核讯号量的使用解释器

在驱动程序中,当多个线程同时访问相同的资源时(驱动中的全局变量时一种典型的

共享资源),可能会引起“竞态“,为此我们必须对共享资源进行并发控制。Linux内核中

解决并发控制的最常用技巧是载流子锁与讯号量(绝大多数时侯作为互斥锁使用)。

ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off){ //获得信号量 if (down_interruptible(&sem)) {  return - ERESTARTSYS; } //将用户空间的数据复制到内核空间的global_var if (copy_from_user(&global_var, buf, sizeof(int))) {  up(&sem);  return - EFAULT; } //释放信号量 up(&sem); return sizeof(int);}

四.POSIX讯号量与SYSTEMV讯号量的比较

1.对POSIX来说,讯号量是个非负整数。常用于线程间同步。而SYSTEMV讯号量则是一个或多个讯号量的集合,它对应的是一个讯号量结构体,这个结构体是为SYSTEMVIPC服务的,讯号量只不过是它的一部份。常用于进程间同步。

2.POSIX讯号量的引用头文件是“”,而SYSTEMV讯号量的引用头文件是

“”。

3.从使用的角度,SystemV讯号量是复杂的,而Posix讯号量是简单。例如,POSIX信

号量的创建和初始化或PV操作就很特别便捷。

五.POSIX讯号量解读

1.无名讯号量

无名讯号量的创建犹如申明通常的变量一样简单,譬如:sem_tsem_id。之后再初始化该无名讯号量,然后就可以放心使用了。

无名讯号量常用于多线程间的同步,同时也用于相关进程间的同步。也就是说,无名讯号量必须是多个进程(线程)的共享变量,无名讯号量要保护的变量也必须是多个进程(线程)的共享变量,这两个条件是缺一不可的。

常见的无名讯号量相关函数:sem_destroy

intsem_init(sem_t*sem,intpshared,unsignedintvalue);

1)pshared==0用于同一多线程的同步;

2)若pshared>0用于多个相关进程间的同步(即由fork形成的)

intsem_getvalue(sem_t*sem,int*sval);

拿回讯号量sem的当前值,把该值保存到sval中。

若有1个或更多的线程或进程调用sem_wait阻塞在该讯号量上,该函数返回两种值:

1)返回0

2)返回阻塞在该讯号量上的进程或线程数量

linux采用返回的第一种策略。

linux多进程信号量_进程间通信信号量_linux 进程通信 信号量

sem_wait(或sem_trywait)相当于P操作,即申请资源。

intsem_wait(sem_t*sem);//这是一个阻塞的函数

测试所指定讯号量的值,它的操作是原子的。

若sem>0,这么它减1并立刻返回。

若sem==0,则睡眠直至sem>0,此时立刻减1,之后返回。

intsem_trywait(sem_t*sem);//非阻塞的函数

其他的行为和sem_wait一样,不仅:

若sem==0,不是睡眠,而是返回一个错误EAGAIN。

sem_post相当于V操作,释放资源。

intsem_post(sem_t*sem);

把指定的讯号量sem的值加1;

呼醒正在等待该讯号量的任意线程。

注意:在这种函数中,只有sem_post是讯号安全的函数,它是可重入函数

(a)无名讯号量在多线程间的同步

无名讯号量的常见用法是即将保护的变量放到sem_wait和sem_post中间所产生的

临界区内linux 进程通信 信号量,这样该变量都会被保护上去,比如:

#include #include #include #include #include int number; // 被保护的全局变量sem_t sem_id;void* thread_one_fun(void *arg){sem_wait(&sem_id);printf("thread_one have the semaphoren");number++;printf("number = %dn",number);sem_post(&sem_id);}void* thread_two_fun(void *arg){sem_wait(&sem_id);printf("thread_two have the semaphore n");number--;printf("number = %dn",number);sem_post(&sem_id);}int main(int argc,char *argv[]){number = 1;pthread_t id1, id2;sem_init(&sem_id, 0, 1);pthread_create(&id1,NULL,thread_one_fun, NULL);pthread_create(&id2,NULL,thread_two_fun, NULL);pthread_join(id1,NULL);pthread_join(id2,NULL);printf("main,,,n");return 0;}

里面的类库,究竟那个线程先申请到讯号量资源,这是随机的。假如想要某个特定的次序的话,可以用2个讯号量来实现。诸如下边的类库是线程1先执行完,之后线程2才继续执行,直到结束。

int number; // 被保护的全局变量sem_t sem_id1, sem_id2;void* thread_one_fun(void *arg){sem_wait(&sem_id1);printf("thread_one have the semaphoren");number++;printf("number = %dn",number);sem_post(&sem_id2);}void* thread_two_fun(void *arg){sem_wait(&sem_id2);printf("thread_two have the semaphore n");number--;printf("number = %dn",number);sem_post(&sem_id1);}int main(int argc,char *argv[]){number = 1;pthread_t id1, id2;sem_init(&sem_id1, 0, 1); // 空闲的sem_init(&sem_id2, 0, 0); // 忙的pthread_create(&id1,NULL,thread_one_fun, NULL);pthread_create(&id2,NULL,thread_two_fun, NULL);pthread_join(id1,NULL);pthread_join(id2,NULL);printf("main,,,n");return 0;}

(b)无名讯号量在相关进程间的同步

说是相关进程,是由于本程序中共有2个进程,其中一个是另外一个的子进程(由fork形成)的。

原本对于fork来说,子进程只承继了父进程的代码副本,mutex理应在兄妹进程中是互相独立的两个变量,但因为在初始化mutex的时侯,由pshared=1指定了mutex处于共享显存区域,所以此时mutex弄成了父女进程共享的一个变量。此时,mutex就可以拿来同步相关进程了。

#include #include #include #include #include #include #include #include #include int main(int argc, char **argv){int fd, i,count=0,nloop=10,zero=0,*ptr;sem_t mutex;//open a file and map it into memoryfd = open("log.txt",O_RDWR|O_CREAT,S_IRWXU);write(fd,&zero,sizeof(int));ptr = mmap( NULL,sizeof(int),PROT_READ |PROT_WRITE,MAP_SHARED,fd,0 );close(fd);/* create, initialize semaphore */if( sem_init(&mutex,1,1) < 0) //{perror("semaphore initilization");exit(0);}if (fork() == 0){ /* child process*/for (i = 0; i < nloop; i++){sem_wait(&mutex);printf("child: %dn", (*ptr)++);sem_post(&mutex);}exit(0);}/* back to parent process */for (i = 0; i < nloop; i++){sem_wait(&mutex);printf("parent: %dn", (*ptr)++);sem_post(&mutex);}exit(0);}

2.有名讯号量

有名讯号量的特征是把讯号量的值保存在文件中。

这决定了它的用途十分广:既可以用于线程,也可以用于相关进程间查看linux是什么系统,甚至是不相关

进程。

(a)有名讯号量能在进程间共享的诱因

因为有名讯号量的值是保存在文件中的,所以对于相关进程来说,子进程是承继了父

进程的文件描述符,这么子进程所承继的文件描述符所指向的文件是和父进程一样的,当

然文件上面保存的有名讯号量值就共享了。

(b)有名讯号量相关函数说明

有名讯号量在使用的时侯,和无名讯号量共享sem_wait和sem_post函数。

linux 进程通信 信号量_linux多进程信号量_进程间通信信号量

区别是有名讯号量使用sem_open取代sem_init,另外在结束的时侯要像关掉文件一样去关掉这个有名讯号量。

(1)打开一个已存在的有名讯号量,或创建并初始化一个有名讯号量。一个单一的调用就完

成了讯号量的创建、初始化和权限的设置。

sem_t*sem_open(constchar*name,intoflag,mode_tmode,intvalue);

name是文件的路径名;

Oflag有O_CREAT或O_CREAT|EXCL两个取值;

mode_t控制新的讯号量的访问权限;

Value指定讯号量的初始化值。

注意:

这儿的name不能写成/tmp/aaa.sem这样的格式,由于在linux下,sem都是创建

在/dev/shm目录下。你可以将name写成“/mysem”或“mysem”,创建下来的文件都

是“/dev/shm/sem.mysem”,千万不要写路径。也千万不要写“/tmp/mysem”之类的。

当oflag=O_CREAT时,若name指定的讯号量不存在时,则会创建一个,但是后

面的mode和value参数必须有效。若name指定的讯号量已存在,则直接打开该讯号量,

同时忽视mode和value参数。

当oflag=O_CREAT|O_EXCL时,若name指定的讯号量已存在,该函数会直接返

回error。

(2)一旦你使用了一讯号量,销毁它们就显得很重要。

在做这个之前,要确定所有对这个有名讯号量的引用都早已通过sem_close()函数

关掉了,之后只需在退出或是退出处理函数中调用sem_unlink()去删掉系统中的讯号量,

注意假如有任何的处理器或是线程引用这个讯号量linux培训机构,sem_unlink()函数不会起到任何的作

用。

也就是说,必须是最后一个使用该讯号量的进程来执行sem_unlick才有效。由于每位

讯号灯有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才会把

name所指的讯号灯从文件系统中删掉。也就是要等待最后一个sem_close发生。

(c)有名讯号量在无相关进程间的同步

后面早已说过,有名讯号量是坐落共享显存区的,这么它要保护的资源也必须是坐落

共享显存区,只有这样能够被无相关的进程所共享。

在下边这个事例中,服务进程和顾客进程都使用shmget和shmat来获取得一块共享内

存资源。之后借助有名讯号量来对这块共享显存资源进行互斥保护。

File1:server.c

#include #include #include #include #include #include #include #include #define SHMSZ 27char SEM_NAME[]= "vik";int main(){char ch;int shmid;key_t key;char *shm,*s;sem_t *mutex;//name the shared memory segmentkey = 1000;//create & initialize semaphoremutex = sem_open(SEM_NAME,O_CREAT,0644,1);if(mutex == SEM_FAILED){perror("unable to create semaphore");sem_unlink(SEM_NAME);exit(-1);}//create the shared memory segment with this keyshmid = shmget(key,SHMSZ,IPC_CREAT|0666);if(shmid<0){perror("failure in shmget");exit(-1);}//attach this segment to virtual memoryshm = shmat(shmid,NULL,0);//start writing into memorys = shm;for(ch='A';ch<='Z';ch++){sem_wait(mutex);*s++ = ch;sem_post(mutex);}//the below loop could be replaced by binary semaphorewhile(*shm != '*'){sleep(1);}sem_close(mutex);sem_unlink(SEM_NAME);shmctl(shmid, IPC_RMID, 0);exit(0);}File 2: client.c#include #include #include #include #include #include #include #include #define SHMSZ 27char SEM_NAME[]= "vik";int main(){char ch;int shmid;key_t key;char *shm,*s;sem_t *mutex;//name the shared memory segmentkey = 1000;//create & initialize existing semaphoremutex = sem_open(SEM_NAME,0,0644,0);if(mutex == SEM_FAILED){perror("reader:unable to execute semaphore");sem_close(mutex);exit(-1);}//create the shared memory segment with this keyshmid = shmget(key,SHMSZ,0666);if(shmid<0){perror("reader:failure in shmget");exit(-1);}//attach this segment to virtual memoryshm = shmat(shmid,NULL,0);//start readings = shm;for(s=shm;*s!=NULL;s++){sem_wait(mutex);putchar(*s);sem_post(mutex);}//once done signal exiting of reader:This can be replaced byanother semaphore*shm = '*';sem_close(mutex);shmctl(shmid, IPC_RMID, 0);exit(0);}

六.SYSTEMV讯号量

进程间通信信号量_linux多进程信号量_linux 进程通信 信号量

这是讯号量值的集合,而不是单个讯号量。相关的讯号量操作函数由引用。

1.讯号量结构体

内核为每个信号量集维护一个信号量结构体,可在找到该定义:struct semid_ds {struct ipc_perm sem_perm; /* 信号量集的操作许可权限 */struct sem *sem_base; /* 某个信号量sem结构数组的指针,当前信号量集中的每个信号量对应其中一个数组元素 */ushort sem_nsems; /* sem_base 数组的个数 */time_t sem_otime; /* 最后一次成功修改信号量数组的时间 */time_t sem_ctime; /* 成功创建时间 */};struct sem {ushort semval; /* 信号量的当前值 */short sempid; /* 最后一次返回该信号量的进程ID 号 */ushort semncnt; /* 等待semval大于当前值的进程个数 */ushort semzcnt; /* 等待semval变成0的进程个数 */};

2.常见的SYSTEMV讯号量函数

(a)关键字和描述符

SYSTEMV讯号量是SYSTEMVIPC(即SYSTEMV进程间通讯)的组成部份,其他的有SYSTEMV消息队列,SYSTEMV共享显存。而关键字和IPC描述符无疑是它们的共同点,也使用它们,就不得不先对它们进行熟悉。这儿只对SYSTEMV讯号量进行讨论。

IPC描述符相当于引用ID号,要想使用SYSTEMV讯号量(或MSG、SHM),就必须用IPC描述符来调用讯号量。而IPC描述符是内核动态提供的(通过semget来获取),用

户难以让服务器和顾客事先认可共同使用那个描述符,所以有时侯就须要到关键字KEY来定位描述符。

某个KEY只会固定对应一个描述符(这项转换工作由内核完成),这样如果服务器和顾客事先认可共同使用某个KEY,这么你们就都能定位到同一个描述符,也能够定位到同

一个讯号量,这样就达到了SYSTEMV讯号量在进程间共享的目的。

(b)创建和打开讯号量

intsemget(key_tkey,intnsems,intoflag)

(1)nsems>0:创建一个信的讯号量集,指定集合中讯号量的数目,一旦创建就不能修改。

(2)nsems==0:访问一个已存在的集合

(3)返回的是一个称为讯号量标示符的整数linux 进程通信 信号量,semop和semctl函数将使用它。

(4)创建成功后讯号量结构被设置:

.sem_perm的uid和gid成员被设置成的调用进程的有效用户ID和有效组ID

.oflag参数中的读写权限位存入sem_perm.mode

.sem_otime被置为0,sem_ctime被设置为当前时间

.sem_nsems被置为nsems参数的值

该集合中的每位讯号量不初始化,这种结构是在semctl,用参数SET_VAL,SETALL

初始化的。

semget函数执行成功后,就形成了一个由内核维持的类型为semid_ds结构体的讯号量

集,返回semid就是指向该讯号量集的引索。

(c)关键字的获取

有多种方式使顾客机和服务器在同一IPC结构上会合:

(1)服务器可以指定关键字IPC_PRIVATE创建一个新IPC结构,将返回的标示符储存在某

处(比如一个文件)便于顾客机取用。关键字IPC_PRIVATE保证服务器创建一个新IPC结

构。此类技术的缺点是:服务器要将整型标示符讲到文件中,之后顾客机在随后又要读文件取得此标示符。

IPC_PRIVATE关键字也可用于父、子关系进程。父进程指定IPC_PRIVATE创建一个新IPC结构,所返回的标示符在fork后可由子进程使用。子进程可将此标示符作为exec函数的一个参数传给一个新程序。

(2)在一个公用头文件中定义一个顾客机和服务器都认可的关键字。之后服务器指定此关键

字创建一个新的IPC结构。这些方式的问题是该关键字可能已与一个IPC结构相结合,在

此情况下,get函数(msgget、semget或shmget)出错返回。服务器必须处理这一错误,删掉已存在的IPC结构,之后试着再创建它。其实,这个关键字不能被别的程序所占用。

进程间通信信号量_linux 进程通信 信号量_linux多进程信号量

(3)顾客机和服务器认同一个路径名和课题ID(课题ID是0~255之间的字符值),之后调用函数ftok将这两个值变换为一个关键字。这样就防止了使用一个已被占用的关键字的

问题。

使用ftok并非高枕无忧。有这样一种例外:服务器使用ftok获取得一个关键字后,该文件就被删掉了,之后重建。此时顾客端借此重建后的文件来ftok所获取的关键字就和服务器的关键字不一样了。所以通常商用的软件都不怎样用ftok。

通常来说,顾客机和服务器起码共享一个头文件,所以一个比较简单的方式是防止使用ftok,而只是在该头文件中储存一个你们都晓得的关键字。

(d)设置讯号量的值(PV操作)

int semop(int semid, struct sembuf *opsptr, size_t nops);(1) semid: 是semget返回的semid(2)opsptr: 指向信号量操作结构数组(3) nops : opsptr所指向的数组中的sembuf结构体的个数struct sembuf {short sem_num; // 要操作的信号量在信号量集里的编号,short sem_op; // 信号量操作short sem_flg; // 操作表示符};

(4)若sem_op是负数,其值就加到semval上,即释放讯号量控制的资源

若sem_op是0,这么调用者希望等到semval变为0,假如semval是0就返回;

若sem_op是正数,这么调用者希望等待semval变为小于或等于sem_op的绝对值

比如,当前semval为2,而sem_op=-3,这么如何办?

注意:semval是指semid_ds中的讯号量集中的某个讯号量的值

(5)sem_flg

SEM_UNDO由进程手动释放讯号量

IPC_NOWAIT不阻塞

到这儿,读者肯定有个疑问:semop希望改变的semval究竟在那里?我们如何没看见有它的痕迹?虽然,上面早已说明了,当使用semget时,就形成了一个由内核维护的讯号量集(其实每位讯号量值即semval也是只由内核能够看得到了),用户能看见的就是返回的semid。内核通过semop函数的参数,晓得应当去改变semid所指向的讯号量的那个semval。

(e)对讯号集推行控制操作(semval的形参等)

int semctl(int semid, int semum, int cmd, ../* union semun arg */);semid是信号量集合;semnum是信号在集合中的序号;semum是一个必须由用户自定义的结构体,在这里我们务必弄清楚该结构体的组成:union semun{int val; // cmd == SETVALstruct semid_ds *buf // cmd == IPC_SET或者 cmd == IPC_STATushort *array; // cmd == SETALL,或 cmd = GETALL};

val只有cmd==SETVAL时才有用,此时指定的semval=arg.val。

注意:当cmd==GETVAL时,semctl函数返回的值就是我们想要的semval。千万不要以为指定的semval被返回到arg.val中。

array指向一个链表,当cmd==SETALL时,就按照arg.array来将讯号量集的所有值都形参;当cmd==GETALL时,就将讯号量集的所有值返回到arg.array指定的链表中。buf表针只在cmd==IPC_STAT或IPC_SET时有用,作用是semid所指向的讯号量集

(semid_ds机构体)。通常情况下不常用,这儿不做谈论。

另外,cmd==IPC_RMID还是比较有用的。

(f)例码

#include #include #include #include static int nsems;static int semflg;static int semid;int errno=0;union semun {int val;struct semid_ds *buf;unsigned short *array;}arg;int main(){struct sembuf sops[2]; //要用到两个信号量,所以要定义两个操作数组int rslt;unsigned short argarray[80];arg.array = argarray;semid = semget(IPC_PRIVATE, 2, 0666);if(semid < 0 ){printf("semget failed. errno: %dn", errno);exit(0);}//获取0th信号量的原始值rslt = semctl(semid, 0, GETVAL);printf("val = %dn",rslt);//初始化0th信号量,然后再读取,检查初始化有没有成功arg.val = 1; // 同一时间只允许一个占有者semctl(semid, 0, SETVAL, arg);rslt = semctl(semid, 0, GETVAL);printf("val = %dn",rslt);sops[0].sem_num = 0;sops[0].sem_op = -1;sops[0].sem_flg = 0;sops[1].sem_num = 1;sops[1].sem_op = 1;sops[1].sem_flg = 0;rslt=semop(semid, sops, 1); //申请0th信号量,尝试锁定if (rslt < 0 ){printf("semop failed. errno: %dn", errno);exit(0);}//可以在这里对资源进行锁定sops[0].sem_op = 1;semop(semid, sops, 1); //释放0th信号量rslt = semctl(semid, 0, GETVAL);printf("val = %dn",rslt);rslt=semctl(semid, 0, GETALL, arg);if (rslt < 0){printf("semctl failed. errno: %dn", errno);exit(0);}printf("val1:%d val2: %dn",(unsigned int)argarray[0],(unsigned int)argarray[1]);if(semctl(semid, 1, IPC_RMID) == -1){Perror(“semctl failure while clearing reason”);}return(0);}

七.讯号量的牛刀小试——生产者与消费者问题

1.问题描述:

有一个宽度为N的缓冲池为生产者和消费者所共有,只要缓冲池未满,生产者便可将

消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中拿走一个消息。生产者往缓冲池

放信息的时侯,消费者不可操作缓冲池,反之亦然。

2.使用多线程和讯号量解决该精典问题的互斥

#include #include #include #define BUFF_SIZE 10char buffer[BUFF_SIZE];char count; // 缓冲池里的信息数目sem_t sem_mutex; // 生产者和消费者的互斥锁sem_t p_sem_mutex; // 空的时候,对消费者不可进sem_t c_sem_mutex; // 满的时候,对生产者不可进void * Producer(){while(1){sem_wait(&p_sem_mutex); //当缓冲池未满时sem_wait(&sem_mutex); //等待缓冲池空闲count++;sem_post(&sem_mutex);if(count < BUFF_SIZE)//缓冲池未满sem_post(&p_sem_mutex);if(count > 0) //缓冲池不为空sem_post(&c_sem_mutex);}}void * Consumer(){while(1){sem_wait(&c_sem_mutex);//缓冲池未空时sem_wait(&sem_mutex); //等待缓冲池空闲count--;sem_post(&sem_mutex);if(count > 0)sem_post(c_sem_nutex);}}int main(){pthread_t ptid,ctid;//initialize the semaphoressem_init(&empty_sem_mutex,0,1);sem_init(&full_sem_mutex,0,0);//creating producer and consumer threadsif(pthread_create(&ptid, NULL,Producer, NULL)){printf("n ERROR creating thread 1");exit(1);}if(pthread_create(&ctid, NULL,Consumer, NULL)){printf("n ERROR creating thread 2");exit(1);}if(pthread_join(ptid, NULL)) /* wait for the producer to finish */{printf("n ERROR joining thread");exit(1);}if(pthread_join(ctid, NULL)) /* wait for consumer to finish */{printf("n ERROR joining thread");exit(1);}sem_destroy(&empty_sem_mutex);sem_destroy(&full_sem_mutex);//exit the main threadpthread_exit(NULL);return 1;}

定期以浅显易懂的方法分享嵌入式知识,关注公众号,加星标,每晚进步一点点。

Tagged:
Author

这篇优质的内容由TA贡献而来

刘遄

《Linux就该这么学》书籍作者,RHCA认证架构师,教育学(计算机专业硕士)。

发表回复