进程与线程的概念

进程、线程的概念

假设我们写一个音乐播放器,在播放音乐的同时会根据按键选择下一首歌。把事情简化为 2 件事:发送
音频数据、读取按键。那可以这样写程序:

int main(int argc, char **argv)
{
	int key;
	while (1)
	{
		key = read_key();
		if (key != -1)
		{
			switch (key)
			{
				case NEXT:
					select_next_music(); // 在 GUI 选中下一首歌
					break;
			}
		}
		else
		{
			send_music();
		}
	}
	return 0;
}

这个程序只有一条主线,读按键、播放音乐都是顺序执行。
无论按键是否被按下, read_key 函数必须马上返回,否则会使得后续的 send_music 受到阻滞导致音乐
播放不流畅。
读取按键、播放音乐能否分为两个程序进行?可以,但是开销太大:读按键的程序,要把按键通知播放
音乐的程序,进程间通信的效率没那么高。
这时可以用多线程之编程,读取按键是一个线程,播放音乐是另一个线程,它们之间可以通过全局变量
传递数据,示意代码如下:

int g_key;
void key_thread_fn()
{
	while (1)
	{
		g_key = read_key();
		if (g_key != -1)
		{
			switch (g_key)
			{
				case NEXT:
					select_next_music(); // 在 GUI 选中下一首歌
					break;
			}
		}
	}
}
void music_fn()
{
	while (1)
	{
		if (g_key == STOP)
			stop_music();
		else
		{
			send_music();
		}
	}
}
int main(int argc, char **argv)
{
	int key;
	create_thread(key_thread_fn);
	create_thread(music_fn);
	while (1)
	{
		sleep(10);
	}
	return 0;
}

这样,按键的读取及 GUI 显示、音乐的播放,可以分开来,不必混杂在一起。
按键线程可以使用阻塞方式读取按键,无按键时是休眠的,这可以节省 CPU 资源。
音乐线程专注于音乐的播放和控制,不用理会按键的具体读取工作。
并且这 2 个线程通过全局变量 g_key 传递数据,高效而简单。
在 Linux 中:资源分配的单位是进程,调度的单位是线程。
也就是说,在一个进程里,可能有多个线程,这些线程共用打开的文件句柄、全局变量等等。
而这些线程,之间是互相独立的,“同时运行”,也就是说:每一个线程,都有自己的栈。如下图示:
在这里插入图片描述