先来个Boost库的例子,主线程为生产者,提供输入,子线程一作为消费者发送消息。
#include <boost/format.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
boost::mutex mtx;
boost::condition producer;
boost::condition consumer;
int MsgNum = 0;
std::string SendBuf;
void SendMsg(int fd);
int main(int argc,char *argv[])
{
int port = 8628;
std::string ip="192.168.18.22"
struct sockaddr_in ,d_addr;
memset(&d_addr,0,sizeof(d_addr));
d_addr.sin_family=AF_INET;
d_addr.sin_port=htons(port);
d_addr.sin_addr.s_addr=inet_addr(ip.c_str());
int sockfd=socket(PF_INET,SOCK_STREAM,0);
if(sockfd<0)
return 0;
if(connect(sockfd,(struct sockaddr *)&d_addr,sizeof(struct sockaddr))<0)
{
printf("connect error\n");
return 0;
}
MsgNum = 0;
boost::thread trd2(boost::bind(&SendMsg, sockfd)); //起子线程发送消息
while(1)
{
boost::mutex::scoped_lock sl(mtx); //占用互斥锁,未占用则阻塞
while(MsgNum>=1)
{
producer.wait(mtx);//如果存在未发送的消息,放开互斥锁并阻塞
}
printf("input string\n");
std::cin>>SendBuf;
MsgNum++;
consumer.notify_one();//通知消费者的条件变量结束wait
}
}
void SendMsg(int fd)
{
while(1)
{
boost::mutex::scoped_lock sl(mtx); //占用互斥锁
while(MsgNum<=0)
{
consumer.wait(mtx); //初始化时MsgNum为0,放开互斥锁并阻塞
}
int n=send(fd, SendBuf.c_str() ,SendBuf.size(),0);
if(n<=0)
{
std::cout<<"send error"<<std::endl;
break;
}
else
std::cout<<"send success"<<std::endl;
MsgNum--;
producer.notify_one();//通知条件变量
}
}
再来个pthread库的例子。
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
static pthread_cond_t cond;
static pthread_mutex_t mtx;
struct node {
int n_number;
struct node *n_next;
} *head = NULL;
/*[thread_func]*/
static void cleanup_handler(void *arg)
{
printf("Cleanup handler of second thread\n");
free(arg);
(void)pthread_mutex_unlock(&mtx);
}
static void *thread_func(void *arg)
{
struct node *p = NULL;
pthread_cleanup_push(cleanup_handler, p);//当线程被取消或者pthread_cleanup_pop被调用且参数非零时,调用压栈的清理函数
while (1)
{
pthread_mutex_lock(&mtx); //这个mutex主要是用来保证pthread_cond_wait的并发性
while (head == NULL)
{
pthread_cond_wait(&cond, &mtx); // pthread_cond_wait会先解锁mtx,然后阻塞,直到再次被唤醒。唤醒后,该进程会先pthread_mutex_lock(&mtx);,再读取资源
}
p = head;
head = head->n_next;
printf("Got %d from front of queue\n", p->n_number);
free(p);
pthread_mutex_unlock(&mtx); //临界区数据操作完毕,释放互斥锁
}
pthread_cleanup_pop(0);
return 0;
}
int main(void)
{
pthread_t tid;
int i;
struct node *p;
pthread_create(&tid, NULL, thread_func, NULL); //子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大
/*[tx6-main]*/
for (i = 0; i < 10; i++) {
p = malloc(sizeof(struct node));
p->n_number = i;
pthread_mutex_lock(&mtx); //需要操作head这个临界资源,先加锁,
p->n_next = head;
head = p;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx); //解锁
sleep(1); //注意,这个sleep必不可少,否则输出逆序。原因:pthread_cond_signal本身只发送通知信号而不是解锁,发送完信号就返回。这一秒的时间是让线程完成工作后再次wait的。
}
printf("thread 1 wanna end the line.So cancel thread 2./n");
pthread_cancel(tid); //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。关于取消点的信息,有兴趣可以google,这里不多说了
pthread_join(tid, NULL);
printf("All done -- exiting/n");
return 0;
}