生产者-消费者问题:

生产者-消费者问题是经典的同步问题,它描述一组生产者进程(线程)向一组消费者进程(线程)提供消息。它们共享一个有界的缓冲池,生产者向其中投放消息,消费者从中取得消息。生产者-消费者问题是许多具体问题中进程(线程)合作的一个很好的抽象。假定缓冲区中有N个位置,每个位置存放一个消息。当缓冲区未满时,生产者可以投入一个消息,否则该进程(线程)阻塞,直到缓冲区内有空位可放;当缓冲区非空时,消费者可以从中取得一个消息,否则该进程(线程)阻塞,直到缓冲区内有消息可取。

为了模拟这一过程,首先需要设置一个大小为N的缓冲区。修改缓冲区时,需要同步各个进程(线程)以免发生错误(向满的缓冲区投放消息或者从空缓冲区内取出消息)。为此,需要设置两个信号量empty和full用以标识缓冲区中空位数和消息数。另外还需要一个互斥锁mutex以互斥地修改缓冲区。为了便于测试,这里缓冲区的大小设置为5,实际情况下,应该尽量大些,以免生产者和消费者相互等待。

Tags: ,,.
  1. 减少pthread_cond_signal和sem_post的调用,只在有必要的时候调用;
  2. 尽量避免pthread_mutex进入竞争态。增大消息队列的大小,可以有效减少竞态条件的出现。

/*
* 此处循环判断的原因如下:假设2个线程在getq阻塞,然后两者都被激活,
* 而其中一个线程运行比较块,快速消耗了2个数据,
* 另一个线程醒来的时候已经没有新数据可以消耗了。
* 另一点,man pthread_cond_wait可以看到,
* 该函数可以被信号中断返回,此时返回EINTR。
* 为避免以上任何一点,都必须醒来后再次判断睡眠条件。
* 更正:pthread_cond_wait是信号安全的系统调用,不会被信号中断。
*/

Tags: ,,.

默认情况下,ubuntu终端的复制、粘贴快捷键是Ctrl+P、Ctrl+V,但ctrl+C、Ctrl+V已经习惯了,总是需要重新设置一下。这在9.04以前一直没出过什么问题,复制和中断程序也没有发生冲突。但9.04就不行了,想终止程序时Ctrl+C一点反应都没有,想必是按键冲突了吧,但平时也懒得去改,今天调的一个程序里面用到了条件变量和互斥锁(mutex),总是发生死锁,只好现Ctrl+Z暂停到后台,然后再kill %1才能将其终止。到后来实在忍不了了!stty -a查看了一下,和^C关联是intr,stty intr ^X把终止键绑定到Ctrl+X上了,剪切是很少用的。

Tags: ,.

表明看来似乎合情合理,由于C++的多态特性,允许我们将一个子类地址赋给父类型的指针pb,释放对象时理所当然的对pb进行delete。但,在程序运行时,并没有输出M destructed…,即D::m的析构函数没有被调用,而m的析构函数是需要D::~D()来调用的,所以子类D的析构函数也没有被调用。这是很容易理解的,因为父类的析构函数不是virtual的。由此,我们得出结论,用来继承的父类的析构函数总应该是virtual的,除非你确定它绝对不会被用于多态。关于这一点,《Effective C++》里面已经讲到了。

除了上面的问题,我们还应该关心的是,尽管析构函数没有被调用,那M::i的空间被释放了吗?It’s a question!由于析构函数没有被调用,那么释放M::i的任务就完全落在了delete身上的了,那么delete做到了吗?It’s a very question!这又回到了上一篇日志中所描述的问题上了。我的观点是delete做到了它应该做的事情,它只负责释放当初new申请的空间,即对象本身,至于对象里面是否有动态申请的内存,那就不是delete而是对象析构函数自己的工作了。

Tags: ,,.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int
main()
{
	pthread_mutex_init(&mutex, NULL); //~ 初始化互斥锁mutex
	pthread_t thread_id;
	void *exit_status;
	pthread_create(&thread_id, NULL, thread_function, NULL); //~ 创建新线程
	for(int i = 0; i < 10; ++i)
	{
		usleep(10000); //~ 延时10ms
		//~ 访问共享数据
		pthread_mutex_lock(&mutex);
		cout<<share<<endl;
		pthread_mutex_unlock(&mutex);
	}
	pthread_join(thread_id, &exit_status); //~ 等待线程结束
	pthread_mutex_destroy(&mutex); //~ 销毁互斥锁
	return 0;
}
Tags: ,.

源码之前,了无秘密。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//~ demo.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <streambuf>
using namespace std;
//~ 测试代码 :)
int main()
{
	ifstream in("demo.cpp");
	char buffer[4096]="original content in this buffer";
	cout<<buffer<<endl;
	streambuf * ptrbuff = in.rdbuf(); //~ 将streambuf与文件句柄关联
	ptrbuf->pubsetbuf(bufer, 4096); //~ 设置缓冲区,即设置in的缓冲区
	cout<<buffer<<endl; //~ 此时bufer里面的内容还是original content in this buffer
	string str;
	in>>str; //~ 真正要输入时bufer才被填充为in的内容
	cout<<str<<endl;
	cout<<buffer<<endl;
	return 0;
}

另外,还有一个filebuf,用法相近。看了很多C++方面的书,从来没有那本书对I/O流做过详细的介绍。C里面有setbuf可以修改缓冲区,但我在fstream里面却没看到这么个setbuf,rdbuf倒是有一个,它返回streambuf类型的指针。搜索streambuf的用法,无果,MSDN里面看到streambuf有一个setbuf的成员,甚喜。编译器说,setbuf是私有的,再看MSDN,还有一个pubsetbuf,哟西!

Tags: ,.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	call ___main
	movl $1,-4(%ebp) ; a
	movl $2,-8(%ebp) ; b
	movl -4(%ebp),%eax ;if/else开始
	cmpl -8(%ebp),%eax
	jge L2
	movl -4(%ebp),%eax
	movl %eax,-12(%ebp)
	jmp L3
	.p2align 4,,7
L2:
	movl -8(%ebp),%eax
	movl %eax,-12(%ebp) ; if/else结束
L3:
	movl -8(%ebp),%eax ; ? :开始
	cmpl -4(%ebp),%eax
	jle L4
	movl -4(%ebp),%eax
L4:
	movl %eax,-12(%ebp) ; ? :结束

if/else用了8条指令,?:用了5条,这个差距可不算小了啊!因为,程序里面是要有循环的,多数循环里面会有分支语句,且很多情况下是二分支。
呃……又学到一个单词,ternary:三元。:-)

Tags: ,.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void reverse(Node * T)
{
	assert(T); //~ 表头非空
	Node* p = T->next, *t;
	if(p)
	{	//~ 将第一个结点,即未来的表尾next域置空
		t = p->next;
		p->next = NULL;
		p = t;
	}
	while(p)
	{	//~ 将余下结点依次插入表头
		t = p->next;
		p->next = T->next;
		T->next = p;
		p = t;
	}
}
Tags: ,.

有一点需要注意的是,由于STL内的容器的析构函数都不是virtual的,所以,继承这些容器的类(或者模板类)不能用于多态!这也是不提倡继承STL容器的原因。

不过,由于上面的代码中mstack继承自STL模板容器vector,其自身并没有任何成员;
继承vector的目的不是使用多态特性,仅仅是复用了vector的接口而已,且复用也仅仅是内部复用;
由于是私有继承,你无法调用父类vector的接口,子类与父类接口并不一致,在语法就不能用于多态;
综上所述,这样的继承并没有什么潜在的危险。

Tags: ,.
Linux Air

对其它所有航空公司都不满的员工决定离开他们自己的航空公司。他们开始自己建造飞机,机票柜台,以及自己铺设飞机跑道。他们只用很少的费用给你提供可打印的机票,但你完全可以自己下载下来打印机票。

当你登机的时候,会有人递给你一个座位,四个螺栓,一个扳手和一本“安装座位-HOWTO.html”手册。一但安装好了,可随意调整或更改的座位可能让你相当地舒服,从飞机离开到目的地,其几乎不会发生一个错误,而且,飞机过程中的飞行餐非常不错。你会想去告诉选乘别的航空公司的乘客你那完美的经历,但你所能得到的回答是,“乘座飞机还要必需要去安装自己的座位?”。

Tags: .