线程概念
线程是CPU调度的基本单位,一个进程下可能有多个线程。在Linux系统中,线程是轻量级进程的概念:LWP。一般我们所说的线程概念是C库当中的概念。 进程:有独立的进程地址空间,有独立的PCB。线程:有独立的PCB,没有独立的进程地址空间。
-
线程共享资源:
- 文件描述符表
- 每种信号的处理方式
- 当前的工作目录
- 用户ID和组ID
- 内存地址空间
-
线程非共享资源
- 线程ID
- 处理器现场(寄存器的值)和栈指针(内核栈)
- 独立的栈空间(用户空间栈)
- errno变量
- 信号屏蔽字
- 调度优先级
-
线程优缺点
线程是操作系统中的一种调度单位,它是比进程更小的能独立运行的基本单位。线程的优点包括:- 更小的资源开销:线程比进程更轻量级,创建和切换线程的开销更小,能更有效地利用系统资源。
- 更高的并发性:线程可以比进程更细粒度地调度,能够更高效地利用多核处理器的性能,提高并发能力。
- 更好的协作性:线程可以共享进程的内存空间和其他系统资源,使得多个线程之间的协作更加方便和高效。
- 更快的响应速度:线程可以快速切换,能够更快地响应用户请求和处理任务。
线程的缺点包括: - 线程之间的相互干扰:由于线程共享进程的内存空间和其他系统资源,因此线程之间的相互干扰可能会导致程序出现问题。
- 线程的调度开销:虽然线程的调度开销比进程小,但频繁地创建和切换线程也会导致一定的性能损失。
- 线程的资源限制:由于线程共享进程的资源,因此线程的资源使用量不能超过进程的资源使用量。
- 线程的通信开销:线程之间的通信需要使用同步机制,如互斥锁、信号量等,这可能会导致一定的性能开销。
线程控制原语
Pthread_self函数
pthread_self 函数是 C 语言中用于获取当前线程标识的函数,属于标准 C 库中的多线程支持函数。
该函数的函数原型为:
#include <pthread.h>
pthread_threadid_t pthread_self(void);
其中,pthread_threadid_t 是一个线程标识符类型,用于表示当前线程的唯一标识。
使用 pthread_self 函数可以获取当前线程的标识符,以便在多线程程序中进行线程识别和处理。例如,可以在循环中使用 pthread_self 函数获取当前线程的标识符,并将其打印出来,以了解程序运行时的线程状态。
需要注意的是,pthread_self 函数只是获取当前线程的标识符,而不是创建或销毁线程。要创建或销毁线程,需要使用其他函数,如 pthread_create 和 pthread_destroy 等。
Pthread_create函数
pthread_create 函数是 C 语言中用于创建新线程的函数,属于标准 C 库中的多线程支持函数。
该函数的函数原型为:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
其中,thread 是指向线程标识符的指针,attr 是指向线程属性的指针,start_routine 是线程运行时的入口函数,arg 是传递给线程的参数。
pthread_create 函数用于创建一个新的线程,并将其返回值保存在 thread 指向的变量中。如果创建成功,返回值将为线程标识符;如果创建失败,返回值为错误代码。
在创建线程时,可以使用 pthread_attr_t 结构体来设置线程属性,如线程名、优先级、堆栈大小等。线程属性可以在创建线程之前设置,也可以在创建线程之后使用 pthread_attr_set 函数进行修改。
需要注意的是,pthread_create 函数只是创建线程,而不是启动线程。要启动线程,需要使用 pthread_start 函数。同时,线程的加入和退出也需要使用相应的函数进行处理,如 pthread_join 和 pthread_exit。
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void *tfn(void *arg) //子线程
{
printf("this is created thread:pid= %d, tid=%lu\n",getpid(),pthread_self());
return NULL;
}
int main(int argc,char *arg[]) //主线程
{
pthread_t tid;
printf("main:pid= %d, tid=%lu\n",getpid(),pthread_self());
int ret=pthread_create(&tid,NULL,tfn,NULL);
if (ret !=0){
perror("pthread_create error");
}
sleep(1);
return 0;
}
循环创建多个子线程
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void *tfn(void *arg) //子线程
{
int i=(int)arg;
sleep(i);
printf("I am %dth thread: pid= %d, tid=%lu\n",i+1,getpid(),pthread_self());
return NULL;
}
int main(int argc,char *arg[]) //主线程
{
pthread_t tid;
int i;
int ret;
for(i=0;i<5;i++)
{
ret=pthread_create(&tid,NULL,tfn,(void *)i);
if (ret!=0)
{
sys_err("pthread_create error");
}
}
sleep(i);
return 0;
}
pthread_exit函数
pthread_exit 函数是 C 语言中用于终止线程执行的函数,用于退出当前线程,属于标准 C 库中的多线程支持函数。该函数的函数原型为:
#include <pthread.h>
int pthread_exit(void *retval);
其中,retval 是指向返回值的指针,用于将线程执行的结果返回给主线程。
pthread_exit 函数用于终止调用该函数的线程,并返回线程执行的结果。如果 retval 指向一个对象,该对象将成为线程的返回值;如果 retval 为 NULL,则表示线程执行成功,返回值为 0;如果 retval 为其他任意值,则表示线程执行失败,返回值为 retval。
在主线程中,可以通过调用 pthread_join 函数等待子线程结束,并获取子线程的返回值。
pthread_join函数
pthread_join 函数是用于等待一个线程结束并返回其结果的函数。它属于 C 语言中的线程库函数,用于多线程程序设计。
在多线程程序中,当一个线程完成任务后,需要通过 pthread_join 函数等待该线程结束,并获取其返回值。pthread_join 函数的语法如下:
int pthread_join(pthread_t thread, void **result);
其中,thread 是一个线程句柄,用于标识要等待的线程;result 是一个指向返回值的指针,用于存储线程的返回值。
当调用 pthread_join 函数时,程序会等待线程结束,并将线程的返回值存储在 result 指向的内存地址中。如果线程在调用 pthread_join 函数之前已经结束,那么 pthread_join 函数会立即返回线程的返回值。
在多线程程序设计中,pthread_join 函数常用于等待子线程完成任务,以便在子线程结束后对结果进行处理。例如,下面的代码创建了一个子线程,并使用 pthread_join 函数等待子线程结束,然后打印子线程的返回值:
#include <pthread.h>
#include <stdio.h>
void *worker_function(void *arg) {
printf("Worker thread is running\n");
sleep(1);
printf("Worker thread has finished\n");
return (void *)1;
}
int main() {
pthread_t worker_thread;
void *result;
pthread_create(&worker_thread, NULL, worker_function, NULL);
pthread_join(worker_thread, &result);
printf("Worker thread returned %d\n", *(int *)result);
return 0;
}
在上面的代码中,worker_function 是一个子线程的函数,它在执行时会打印一些信息,然后返回一个整数值。在主函数中,我们创建了一个线程句柄 worker_thread,并使用 pthread_create 函数启动了子线程。然后,我们使用 pthread_join 函数等待子线程结束,并获取其返回值。最后,我们使用 printf 函数打印子线程的返回值。
总的来说,pthread_join 函数是 C 语言中用于等待线程结束并获取其返回值的重要函数,它在多线程程序设计中起到了关键作用。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
struct thrd{
int var;
char str[256];
};
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void *tfn(void *arg) //子线程
{
struct thrd *tval;
tval=malloc(sizeof(tval));
tval->var=100;
strcpy(tval->str,"hello thread");
return (void *)tval;
}
int main(int argc,char *arg[]) //主线程
{
pthread_t tid;
struct thrd *retval;
int i;
int ret;
ret=pthread_create(&tid,NULL,tfn,NULL);
if(ret!=0)
sys_err("pthread_create error");
ret=pthread_join(tid,(void **)&retval);
if(ret!=0)
sys_err("pthread_join error");
printf("child thread exit with var=%d, str=%s\n",retval->var,retval->str);
pthread_exit(NULL);
return 0;
}
pthread_cancel函数
pthread_cancel 函数是用于取消一个线程的执行的函数。它属于 C 语言中的线程库函数,用于多线程程序设计。
在多线程程序中,当需要取消一个线程的执行时,可以使用 pthread_cancel 函数,注意,需要取消点才可,如果子进程没有到达取消点,那么pthread_cancel无效,我们可以在程序中手动添加一个取消点.使用pthread_testcancel()
,成功被pthread_cancel()杀死的线程返回-1值,可用pthread_join
回收这个值。pthread_cancel 函数的语法如下:
int pthread_cancel(pthread_t thread);
其中,thread 是一个线程句柄,用于标识要取消的线程。
当调用 pthread_cancel 函数时,它会尝试取消指定的线程。如果线程正在执行,那么 pthread_cancel 函数会发送一个取消信号给线程,使得线程立即停止执行。如果线程已经结束,那么 pthread_cancel 函数会立即返回 0。
在多线程程序设计中,pthread_cancel 函数常用于取消正在执行的线程,以便在线程结束前停止其执行。例如,下面的代码创建了一个子线程,并使用 pthread_cancel 函数取消子线程的执行:
#include <pthread.h>
#include <stdio.h>
void *worker_function(void *arg) {
printf("Worker thread is running\n");
sleep(1);
printf("Worker thread has finished\n");
return (void *)1;
}
int main() {
pthread_t worker_thread;
void *result;
pthread_create(&worker_thread, NULL, worker_function, NULL);
sleep(2);
pthread_cancel(worker_thread);
printf("Worker thread has been canceled\n");
pthread_join(worker_thread, &result);
printf("Worker thread returned %d\n", *(int *)result);
return 0;
}
在上面的代码中,worker_function 是一个子线程的函数,它在执行时会打印一些信息,然后返回一个整数值。在主函数中,我们创建了一个线程句柄 worker_thread,并使用 pthread_create 函数启动了子线程。然后,我们使用 pthread_cancel 函数取消了子线程的执行。最后,我们使用 pthread_join 函数等待子线程结束,并获取其返回值。
总的来说,pthread_cancel 函数是 C 语言中用于取消线程执行的函数,它在多线程程序设计中起到了关键作用。
pthread_detach函数
pthread_detach 函数是用于分离线程的函数。它属于 C 语言中的线程库函数,用于多线程程序设计。
在多线程程序中,当一个线程完成任务后,可以使用 pthread_detach 函数将其分离,使其成为独立运行的线程。pthread_detach 函数的语法如下:
#include <pthread.h>
#include <stdio.h>
void *worker_function(void *arg);
int main() {
pthread_t worker_thread;
void *result;
pthread_create(&worker_thread, NULL, worker_function, NULL);
sleep(1);
pthread_detach(worker_thread);
printf("Worker thread has been detached\n");
pthread_join(worker_thread, &result);
printf("Worker thread returned %d\n", *(int *)result);
return 0;
}
在上面的代码中,worker_function 是一个子线程的函数,它在执行时会打印一些信息,然后返回一个整数值。在主函数中,我们创建了一个线程句柄 worker_thread,并使用 pthread_create 函数启动了子线程。然后,我们使用 pthread_detach 函数将子线程分离,使其成为独立运行的线程。最后,我们使用 pthread_join 函数等待子线程结束,并获取其返回值。
总的来说,pthread_detach 函数是 C 语言中用于分离线程的函数,它在多线程程序设计中起到了关键作用。
检查出错返回(线程中使用):
fprintf(stderr,"xxx error :%s\n",strerror(ret));
进程和线程控制原语对比
线程属性
线程属性是指用于描述线程特征和状态的属性。在计算机编程中,线程属性通常包括以下几个方面:
- 线程 ID:线程的唯一标识符,用于区分不同线程。每个线程都有一个唯一的 ID,可以在程序中使用。
- 线程名称:线程的名称,用于描述线程的功能和用途。线程名称通常是字符串类型的,可以在程序中设置和修改。
- 线程状态:线程的执行状态,包括运行中、等待中、阻塞中和终止中等。线程状态可以通过线程属性来查询和修改。
- 线程优先级:线程的执行优先级,用于决定线程的执行顺序。线程优先级通常是一个整数值,可以在程序中设置和修改。
- 线程栈大小:线程的栈大小,用于存储线程执行时的局部变量和函数调用时的临时数据。线程栈大小通常是一个整数值,可以在程序中设置和修改。
- 线程执行时间:线程执行的时间,用于衡量线程的执行效率。线程执行时间通常是一个浮点数,可以在程序中查询和修改。
以上线程属性并非所有编程语言和操作系统都支持,具体取决于编程语言和操作系统的线程特性。
线程的分离状态
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
void *tfn(void *arg) //子线程
{
printf("this is created thread:pid= %d, tid=%lu\n",getpid(),pthread_self());
return NULL;
}
int main(int argc,char *arg[]) //主线程
{
pthread_t tid;
pthread_attr_t attr;
int ret=pthread_attr_init(&attr);
if(ret!=0){
fprintf(stderr,"attr_init eror:%s\n",strerror(ret));
exit(1);
}
ret=pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); //设置线程属性为分离属性
if(ret!=0){
fprintf(stderr,"attr_setdetachstate eror:%s\n",strerror(ret));
exit(1);
}
ret=pthread_create(&tid,&attr,tfn,NULL);
if (ret !=0){
perror("pthread_create error");
}
ret=pthread_attr_destroy(&attr);
if(ret!=0){
fprintf(stderr,"attr_destory eror:%s\n",strerror(ret));
exit(1);
}
ret=pthread_join(tid,NULL);
if(ret!=0){
fprintf(stderr,"join eror:%s\n",strerror(ret));
exit(1);
}
printf("main:pid= %d, tid=%lu\n",getpid(),pthread_self());
return 0;
}
线程使用注意事项
线程同步
线程同步是指在多线程程序中,多个线程之间需要共享某些资源或者执行顺序需要相互依赖时,通过一定的机制来协调各个线程的执行过程,确保程序的正确性和可靠性。
线程同步的主要目的是避免多个线程之间由于竞争资源或者执行顺序不当而导致的数据不一致、死锁等问题。常见的线程同步方法包括:
- 互斥锁:通过给共享资源加锁的方式来实现线程之间的互斥访问。当一个线程获取了锁之后,其他线程就需要等待锁释放后才能访问共享资源。
- 信号量:是一个计数器,用于表示某个共享资源的可用数量。当一个线程需要访问共享资源时,先通过原子操作将信号量减 1,表示资源已被占用;当线程释放资源时,通过原子操作将信号量加 1,表示资源已释放。
- 条件变量:用于线程之间的协调和同步。当一个线程需要等待某个条件满足时,可以通过等待该条件变量来阻塞自己;而其他线程可以通过唤醒该条件变量来通知该线程条件已经满足。
- 读写锁:是一种特殊的互斥锁,用于在读多写少的场景下提高程序的并发性能。读写锁允许多个线程同时读取共享资源,但在写操作时需要互斥,即只允许一个写线程访问共享资源。
- 自旋锁:与互斥锁类似,也是用于实现线程之间的互斥访问。不同的是,当一个线程尝试获取自旋锁时,如果该锁已被占用,则该线程会一直循环等待直到获取到锁为止。自旋锁适用于锁的占用时间比较短的情况,因为自旋锁需要不断占用 CPU 资源来等待锁的释放。
加锁步骤:
关于互斥锁(pthread_mutex_t)的使用:
- 首先,创建一个互斥锁对象 lock。
- 使用 pthread_mutex_init 函数初始化互斥锁,设置锁的类型(如 PTHREAD_MUTEX_ERRORCHECK)、锁定方式(如 PTHREAD_MUTEX_NORMAL)和阻塞时间(如 PTHREAD_MUTEX_BLOCKING)等属性。
- 使用 pthread_mutex_lock 函数加锁,使共享资源在访问时不被其他线程干扰。
- 在加锁后,访问共享数据(如 stdout),进行相应的操作。
- 使用 pthread_mutex_unlock 函数解锁互斥锁,释放对共享资源的访问权限,以便其他线程访问。
- 在不需要使用互斥锁时,使用 pthread_mutex_destroy 函数销毁互斥锁,释放其占用的资源。
互斥锁是一种线程同步机制,用于保护共享资源在多线程访问时不发生竞争条件。通过初始化、加锁、解锁和销毁等操作,可以实现对共享资源的安全访问。在编写多线程程序时,要根据实际需求选择合适的同步机制,以确保程序的正确性和可靠性。
restric关键字:
restrict 是一个 C 语言关键字,用于限制函数或变量的作用域。在使用 restrict 关键字时,需要将其置于函数或变量声明之前。它的作用是限制函数或变量的作用域,使其只能在声明它的文件中使用,不能被其他文件中的函数或变量访问。
restrict 关键字的作用是为了提高程序的安全性和可维护性。通过限制函数或变量的作用域,可以避免在其他文件中误用或滥用该函数或变量,从而降低程序出现漏洞的风险。此外,限制作用域还可以提高程序的可读性和可维护性,因为读者或维护者只需要关注声明该函数或变量的文件,而不需要担心其他文件中的相同名称的函数或变量。
总之,restrict 关键字在 C 语言编程中具有重要的作用,用于限制函数或变量的作用域,提高程序的安全性和可维护性。在编写程序时,我们应该根据实际需求合理地使用 restrict 关键字,从而使程序更加安全、可读和易于维护。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
pthread_mutex_t mutex;
void *tfn(void *arg) //子线程
{
srand(time(NULL));
while(1)
{
pthread_mutex_lock(&mutex);
printf("hello ");
sleep(rand()%3);
printf("world\n");
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
return NULL;
}
int main(int argc,char *arg[]) //主线程
{
pthread_t tid;
srand(time(NULL));
int ret=pthread_mutex_init(&mutex,NULL);
if (ret!=0)
{
fprintf(stderr,"mutex init error: %s\n",strerror(ret));
exit(1);
}
pthread_create(&tid,NULL,tfn,NULL);
while(1)
{
pthread_mutex_lock(&mutex);
printf("HELLO ");
sleep(rand()%3);
printf("WORLD\n");
pthread_mutex_unlock(&mutex);
sleep(rand()%3);
}
pthread_join(tid,NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
死锁
死锁是指在多进程或多线程程序中,多个进程或线程之间由于竞争资源或者执行顺序不当而导致的一种僵局。当发生死锁时,各个进程或线程都无法继续执行,系统陷入瘫痪状态。
死锁产生的原因主要有以下几点:
- 竞争资源:多个进程或线程同时争夺有限的共享资源,如互斥锁、信号量等,导致资源分配不足,从而发生死锁。
- 进程间通信:进程之间通过管道、消息队列等方式进行通信时,由于通信量不足或通信方式不当,导致进程间数据同步出现问题,从而引发死锁。
- 执行顺序:多个进程或线程的执行顺序不当,如循环等待、饥饿等待等,导致进程或线程之间无法相互推进,最终陷入死锁。
要避免死锁,可以采取以下策略:
- 避免竞争资源:尽量使用非共享资源,如独占设备、独占数据结构等,减少竞争资源的使用。
- 同步访问:对于共享资源,采用同步访问机制,如互斥锁、信号量等,确保同一时刻只有一个进程或线程可以访问共享资源。
- 避免饥饿等待:在进程或线程之间设置适当的优先级,避免低优先级进程或线程长时间等待高优先级进程或线程,从而引发死锁。
- 检测和解除死锁:在程序中添加死锁检测和解除死锁的代码,及时发现并解决死锁问题。
生产者与消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
void err_thread(int ret,char *str)
{
if(ret!=0)
{
fprintf(stderr,"%s:%s\n",str,strerror(ret));
pthread_exit(NULL);
}
}
struct msg{
int num;
struct msg *next;
};
struct msg *head;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; //定义初始化一个互斥量
pthread_cond_t has_data=PTHREAD_COND_INITIALIZER; //定义初始化一个条件变量
void *producer(void *arg)
{
while(1){
struct msg *mp=malloc(sizeof(struct msg));
mp->num=rand()%1000+1; //模拟生产一个数据
printf("-----producer:%d\n",mp->num);
pthread_mutex_lock(&mutex); //加锁互斥量
mp->next=head;
head=mp;
pthread_mutex_unlock(&mutex); //解锁互斥量
pthread_cond_signal(&has_data); //唤醒阻塞在条件变量has_data上的线程
sleep(rand()%3);
}
return NULL;
}
void *consumer(void *arg)
{
while(1){
struct msg *mp;
pthread_mutex_lock(&mutex); //加锁互斥量
while (head==NULL)
{
pthread_cond_wait(&has_data,&mutex); //阻塞等待条件变量
} //
mp=head;
head=mp->next;
pthread_mutex_unlock(&mutex); //解锁互斥量
printf("-----consumer id:%lu :%d\n",pthread_self(),mp->num);
free(mp);
sleep(rand()%3);
}
return NULL;
}
int main(int argc,char *argv[])
{
int ret;
pthread_t pid,cid;
srand(time(NULL));
ret=pthread_create(&pid,NULL,producer,NULL); //生产者
if(ret!=0)
err_thread(ret,"pthread_create producer error");
ret=pthread_create(&cid,NULL,consumer,NULL); //消费者
if(ret!=0)
err_thread(ret,"pthread_create consumer error");
ret=pthread_create(&cid,NULL,consumer,NULL); //消费者
if(ret!=0)
err_thread(ret,"pthread_create consumer error");
ret=pthread_create(&cid,NULL,consumer,NULL); //消费者
if(ret!=0)
err_thread(ret,"pthread_create consumer error");
pthread_join(pid,NULL);
pthread_join(cid,NULL);
return 0;
}
信号量
信号量是一种同步原语,用于在多进程或多线程程序中控制并发访问共享资源。它通常由一个整数计数器和一组原子操作组成,用于管理对共享资源的访问。sem_init 是一个用于初始化信号量的函数,它通常与信号量相关的其他函数一起使用,如 sem_wait、sem_post 等。
以下是 sem_init 函数的原型:
int sem_init(sem_t *sem, const char *name, int nsems, sem_ flag_t flags);
其中,sem 是一个指向信号量结构的指针,name 是一个字符串,用于给信号量命名,nsems 是一个非负整数,表示信号量的初始值,flags 是一个信号量标志,用于指定信号量的行为。
sem_init 函数返回一个整数,表示成功初始化信号量,或者返回–1,表示初始化信号量失败。
与 sem_init 函数相关的其他函数原型如下:
- sem_wait 函数:用于等待信号量减 1。
int sem_wait(sem_t *sem);
- sem_post 函数:用于发送信号量加 1。
int sem_post(sem_t *sem);
- sem_trywait 函数:用于尝试等待信号量减 1,如果信号量值已经为 0,则返回–1。
int sem_trywait(sem_t *sem);
- sem_timedwait 函数:用于等待信号量减 1,如果在指定时间内信号量值未变为 0,则返回–1。
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
这些函数通常与信号量结构一起使用,用于实现多进程或多线程之间的同步。以下是使用信号量之后的生产者和消费者模型:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <semaphore.h>
#define NUM 5
int queue[NUM];
sem_t blank_number,product_number;
void *producer(void *arg)
{
int i=0;
while(1){
sem_wait(&blank_number);
queue[i]= rand()%1000 +1;
printf("++++product++++: %d\n",queue[i]);
sem_post(&product_number);
i=(i+1)%NUM;
sleep(rand()%1);
}
}
void *consumer(void *arg)
{
int i=0;
while(1){
sem_wait(&product_number);
printf("----Consume----: %d\n",queue[i]);
queue[i]=0;
sem_post(&blank_number);
i=(i+1)%NUM;
sleep(rand()%3);
}
}
int main(int argc,char *argv[])
{
pthread_t pid,cid;
sem_init(&blank_number,0,NUM);
sem_init(&product_number,0,0);
pthread_create(&pid,NULL,producer,NULL);
pthread_create(&cid,NULL,consumer,NULL);
pthread_join(pid,NULL);
pthread_join(cid,NULL);
sem_destroy(&blank_number);
sem_destroy(&product_number);
return 0;
}