C语言中 怎么实现双线程 或者 父子线程啊 用C语言开多线程,想让多个相同的子线程同时运行,怎么实现

C\u8bed\u8a00\u5982\u4f55\u5b9e\u73b0\u591a\u7ebf\u7a0b\u540c\u65f6\u8fd0\u884c

1\u3001\u70b9\u51fb\u83dc\u5355\u680f\u7684\u201cProject\u201d\u9009\u9879\u5361\uff0c\u4e0b\u62c9\u5217\u8868\u7684\u6700\u540e\u4e00\u9879\u201cProject options...\u201d\u662f\u5bf9\u5f53\u524d\u5de5\u7a0b\u7684\u7684\u5c5e\u6027\u8fdb\u884c\u8bbe\u7f6e\u7684\u3002

2\u3001\u9009\u62e9\u5f39\u51fa\u5bf9\u8bdd\u6846\u4e2d\u7684\u201cCompiler\u201d\u9009\u9879\u5361\u3002

3\u3001\u5c06\u5176\u4e2d\u7684\u201cRuntime Library\u201d\u7684\u9009\u62e9\u6539\u4e3a\u201cMultithreaded (LIB)\u201d\u3002

4\u3001\u5c06\u770b\u5230\u5bf9\u8bdd\u6846\u6700\u4e0b\u9762\u7684\u6587\u672c\u6846\u4e2d\u53d1\u751f\u4e86\u4e00\u4e9b\u53d8\u5316\uff0c\u65b0\u589e\u4e86\u201c-MT\u201d\u9009\u9879\uff0c\u8fd9\u4e0e\u7f16\u8bd1\u5668\u4e00\u5f00\u59cb\u6240\u62a5\u7684\u9519\u8bef\u63d0\u793a\u7ed9\u51fa\u7684\u89e3\u51b3\u65b9\u6848\u4e00\u81f4\u3002

5\u3001\u9875\u9762\u7684\u8bbe\u7f6e\u5b8c\u6210\u540e\uff0c\u518d\u5bf9\u8be5\u6e90\u7801\u8fdb\u884c\u7f16\u8bd1\u65f6\uff0c\u5c31\u80fd\u6109\u5feb\u5730\u770b\u5230\u7f16\u8bd1\u5b8c\u5168\u6210\u529f\u3002

\u5de5\u4f5c\u7ebf\u7a0b\u662f\u5904\u7406\u540e\u53f0\u5de5\u4f5c\u7684\uff0c\u521b\u5efa\u4e00\u4e2a\u7ebf\u7a0b\u975e\u5e38\u7b80\u5355\uff0c\u53ea\u9700\u8981\u4e24\u6b65\uff1a\u5b9e\u7ebf\u7ebf\u7a0b\u51fd\u6570\u548c\u5f00\u59cb\u7ebf\u7a0b.\u4e0d\u9700\u8981\u7531CWinThread\u6d3e\u751f\u7c7b,\u4f60\u53ef\u4ee5\u4e0d\u52a0\u4fee\u6539\u5730\u4f7f\u7528CWinThread\u3002
AfxBeginThread\u6709\u4e24\u79cd\u5f62\u5f0f\uff0c\u4e00\u79cd\u662f\u7528\u6765\u521b\u5efa\u7528\u6237\u754c\u9762\u7ebf\u7a0b\u7684\uff0c\u53e6\u4e00\u79cd\u5c31\u662f\u7528\u6765\u521b\u5efa\u5de5\u4f5c\u7ebf\u7a0b\u7684.\u4e3a\u4e86\u5f00\u59cb\u6267\u884c\u7ebf\u7a0b\uff0c\u53ea\u9700\u8981\u5411AfxBeginThread\u63d0\u4f9b\u4e0b\u9762\u7684\u53c2\u6570\u5c31\u53ef\u4ee5\u4e86.
1.\u7ebf\u7a0b\u51fd\u6570\u7684\u5730\u5740
2.\u4f20\u9001\u5230\u7ebf\u7a0b\u51fd\u6570\u7684\u53c2\u6570
3.\uff08\u53ef\u9009\u7684\uff09\u7ebf\u7a0b\u7684\u4f18\u5148\u7ea7\uff0c\u53ef\u53c2\u9605::SetThreadPriority
4.\uff08\u53ef\u9009\u7684\uff09\u7ebf\u7a0b\u5f00\u59cb\u65f6\u5019\u7684\u72b6\u6001,\u53ef\u8bbe\u7f6e\u4e3aCREATE_SUSPENEDE
5.\uff08\u53ef\u9009\u7684\uff09\u7ebf\u7a0b\u7684\u5b89\u5168\u5c5e\u6027,\u8bf7\u53c2\u9605SECURITY_ATTRIBUTES
\u5b9e\u4f8b\u4ee3\u7801
UINT ThreadProc(LPVOID pParam)
{
return 0;//\u7ebf\u7a0b\u6210\u529f\u5b8c\u6210
}
CWinThread* AfxBeginThreadProc,//\u7ebf\u7a0b\u51fd\u6570\u5730\u5740
LPVOID pParam,//\u7ebf\u7a0b\u53c2\u6570
int nPriority=THREAD+PRIORITY_NOMAL,//\u7ebf\u7a0b\u4f18\u5148\u7ea7
int nStackSize=0,//\u7ebf\u7a0b\u5806\u6808\u5927\u5c0f\uff0c\u9ed8\u8ba4\u4e3a1M
DWORD dwCreateFlags=0,
LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL
);

通常使用CreateThread函数来创建新的线程.(Unix下使用pthread_create函数)
首先指出,线程与线程之间,是并列关系,不会存在"父子线程"的概念.
在Windows平台下,CreateThread函数包含在 Windows.h 文件内,包含此文件即可正常使用.
以下为CreateThread函数的声明:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//指向安全性属性描述结构体的
//指针,通常可以忽略的.
SIZE_T dwStackSize,//指定新线程初始的栈大小,若不关心,可以用0填充,来要求使用
//默认值

LPTHREAD_START_ROUTINE lpStartAddress,//用来充当线程的函数的指针.
LPVOID lpParameter,//要传递给函数的参数,这个值本身就是那个参数,而不是参数的地址
DWORD dwCreationFlags,//创建的方式,0表示正常,创建后立即开始运行
LPDWORD lpThreadId//用来接受函数反馈的线程ID的指针.
);

用来充当新的线程的函数格式:
DWORD WINAPI ThreadProc(LPVOID);

CreateThread函数若成功了,返回新线程的句柄,若失败了,则返回NULL.

若用CREATE_SUSPENDED填充dwCreation Flags则创建的线程先挂起来,并不直接开始运行,要用ResumeThread函数恢复线程,才能继续运行.

运行一个程序,这个运行实体就是一个“进程”。

例如,用鼠标双击IE浏览器的图标,你运行了一个IE“进程”。第一个窗未关,你又用鼠标双击IE浏览器的图标,又出来一个浏览器的窗。这时,你运行了同一个程序的两个进程。

对于自己写的程序也如此。运行它,这个运行实体就是一个“进程”。同时运行两个,就是两个进程。计算机分别对两个进程分配资源,直到进程结束,收回资源。

线程是进程里真真跑的线路,真真执行的运算,每个进程有一个主线程。进程里可以开第二第三条新的执行线路,gcc 用 pthread_create(),VC++ 用 CreateThread(), 这就叫双线程和多线程。进程是线程的容器,同一进程的线程共享它们进程的资源。线程里建的线程就是父子线程。

两个或多个进程协同工作时,需要互相交换信息,有些情况下进程间交换的少量信息,有些情况下进程间交换大批信息。这就要通讯。通讯方式不止一种。管道就是一种。VC++ 用 CreatePipe() 函数建立。

管道的实质是一个共享文件,可借助于文件系统的机制实现,创建、打开、关闭和读写.

一个进程正在使用某个管道写入或读出数据时,另一个进程就必须等待. 发送者和接收者双方必须知道对方是否存在,如果对方已经不存在,就没有必要再发送信息.,发送信息和接收信息之间要协调,当写进程把一定数量的数据写入管道,就去睡眠等待,直到读进程取走数据后,把它唤醒。

VC++ 线程例子:
#include <windows.h>
#include <iostream.h>

DWORD WINAPI fun1(LPVOID lp);
DWORD WINAPI fun2(LPVOID lp);
int piao=500;

int main()
{
HANDLE pthread1,pthread2;
pthread1=CreateThread(0,0,fun1,0,0,0);
pthread2=CreateThread(0,0,fun2,0,0,0);
CloseHandle(pthread1);
CloseHandle(pthread2);
Sleep(3000);
return 0;

}

DWORD WINAPI fun1(LPVOID lp)
{
while(1)
{

if(piao>0)
cout<< "thread-1-"<< piao--<<endl;
else
break;
}
return 0;
}

DWORD WINAPI fun2(LPVOID lp)
{
while(1)
{
if(piao>0)
cout<<"thread-2-"<<piao--<<endl;
else
break;
}
return 0;
}

===================================
建管道函数原形:
BOOL CreatePipe(
PHANDLE hReadPipe, // read handle
PHANDLE hWritePipe, // write handle
LPSECURITY_ATTRIBUTES lpPipeAttributes, // security attributes
DWORD nSize // pipe size
);

我们进行多线程编程,可以有多种选择,可以使用WindowsAPI,如果你在使用GTK,也可以使用GTK实现了的线程库,如果你想让你的程序有更多的移植性你最好是选择POSIX中的Pthread函数库,我的程序是在Linux下写的,所以我使用了Pthread库(是不是很伤心,我知道有不少人期待的是WindowsAPI的,好吧,有机会以后再讲那个,现在先把这一系列专题写完 ^_^)

如果你用的是LINUX/UNIX/MacOSX,那么我们已经可以开始了,如果你用的是WINDOWS,那么你需要从网站上下载PTHREAD的WINDOWS开发包,所幸他非常的小。网站地址是http://sourceware.org/pthreads-win32/

先来看一个基本的例子:

复制内容到剪贴板
代码:
#include <pthread.h>
#include <iostream>

using namespace std;

void* tprocess1(void* args){
while(1){
cout << "tprocess1" << endl;
}
return NULL;
}

void* tprocess2(void* args){
while(1){
cout << "tprocess2" << endl;
}
return NULL;
}

int main(){
pthread_t t1;
pthread_t t2;
pthread_create(&t1,NULL,tprocess1,NULL);
pthread_create(&t2,NULL,tprocess2,NULL);
pthread_join(t1,NULL);
return 0;
}在上面的例子中,我们首先加入了pthread.h文件包含,这是所以pthread多线程程序所必须的,接着是iostream我们进行输入输出时要用到,接着就是两个函数的定义,这和普通的函数没有什么区别,之所以写成的 复制内容到剪贴板
代码:
void* tprocess1(void* args)这样的形式,完全是为了迎合pthread_create函数的参数类型,你也可以不这样定义,只要在调用pthread_create创建线程的时候强制转换一下指针类型就可以了。

这两个函数将被用做线程的执行体,也就是说在两个线程里同时运行这两个函数。

现在我们来看main函数,和pthread有关的调用都在这里了。
pthread_t是线程结构,用来保存线程相关数据,你也可以理解为是线程类型,声明一个线程对象(变量)。 复制内容到剪贴板
代码:
pthread_t t1;
pthread_t t2;这里我们声明了两个线程变量t1,t2 复制内容到剪贴板
代码:
pthread_create(&t1,NULL,tprocess1,NULL);
pthread_create(&t2,NULL,tprocess2,NULL);这两句非常重要,pthread_create用来创建线程并启动,他的原型是 复制内容到剪贴板
代码:
int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg); 我们可以知道第一个参数是线程指针,第二参数是线程属性指针,线程属性pthread_attr_t用来指定线程优先级等属性,一般的情况下,我们没有必要修改,使用默认属性来构造线程,所以这里一般取NULL,我们也是这样做的,第三个参数是一个函数指针(函数指针?什么东西,没听说过啊?……巨晕,好嘛,你复习一下C或是C++指针那部分吧)就是线程要执行的代码,这里我们分别要执行tprocess1 tprocess2就写成了上面的样子,这里这个函数指针的类型定义是返回一个空类型指针,接收一个空类型指针参数的函数指针,如果你的函数不是这个定义,那就可以直接转化一下就可以了。

写完这两行代码,两个线程就已经执行起来了,但是如果你省略了 复制内容到剪贴板
代码:
pthread_join(t1,NULL);
然后尝试编译运行程序的时候你会发现程序似乎什么也没干就退出了,是的,那是因为程序的主线程退出的时候操作系统会关闭应用程序使用的所有资源,包括线程……所以在main函数结束前我们得想办法让程序停下来,pthread_join方法的功能就是等待线程结束,要等的线程就是第一个参数,程序会在这个地方停下来,直到线程结束,第二个参数用来接受线程函数的返回值,是void**类型的指针,如果没有返回值,就直接设为NULL吧。

程序写好了,我们怎么编译运行它呢?
如果你使用的是Linux:
在终端里输入
g++ thread.cpp -othread -lpthread
./thread
就可以完成程序的编译及运行

如果你用的是VC:
在工程属性里加入开发包里的几个库文件
把那几个DLL文件放到你的工程路径里,也就是程序运行时候的工作路径,这个在VC6和2005里似乎不太一样,如果你不确定,那就直接放到SYSTEM32里吧。。。
下面的工作就非常简单了
点运行,提示编译,就确定,好了,结果出来了。。。

是不是感觉多线程如此的简单,短短几行代码就搞定了,我想你已经可以写出一个简单的多线程程序了吧,呵呵,其实问题没有这么简单,多线程我们还要面对线程同步的问题,我会在下一个专题里给大家讲到。

扩展阅读:c++编程 ... c#多线程有几种实现方法 ... cpu100%是否很伤害电脑 ... c# cad线 去除自相交 ... c++教程 ... c语言怎么多行同时输出 ... 如何实现多行输入 ... c语言可以多线程吗 ... c语言如何实现输入占几行 ...

本站交流只代表网友个人观点,与本站立场无关
欢迎反馈与建议,请联系电邮
2024© 车视网