GVKun编程网logo

pthread编程(3)——线程除法溢出(pthread 线程池)

1

如果您对pthread编程感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于pthread编程的详细内容,我们还将为您解答3——线程除法溢出的相关问题,并且为您提供关于c#学习

如果您对pthread编程感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于pthread编程的详细内容,我们还将为您解答3——线程除法溢出的相关问题,并且为您提供关于c#学习笔记——进程(process)与线程(thread)、c++多线程编程之CreateThread与_beginthreadex本质区别、Delphi Thread 多线程编程(6)、Delphi Thread线程编程(4)的有价值信息。

本文目录一览:

pthread编程(3)——线程除法溢出(pthread 线程池)

pthread编程(3)——线程除法溢出(pthread 线程池)

#include <pthread.h>
#include <signal.h>
#include <stdio.h>

#define ERROR printf("error @ %s line %d\n", __FILE__, __LINE__ );

void thread_cleanup( void *arg )
{
	printf( "cleanup is called\n" );
} 

void* threadfn_exception( void *arg )
{
	int i = 3;
	
	i /= 0;

	return NULL;
}

// FIXME
// endless output: catch a SIGFPE signal

void sigfpe_handler( int sig )
{
	printf( "catch a SIGFPE signal\n" );
}  

// exceptions in a thread may cause the whole process to be terminated!!

int main(int argc, char const *argv[])
{
	pthread_t thread;
	
	// if we set the handler to SIG_IGN/SIG_DFL, the process will be killed
	// signal does''t work well if portability is taken into consideration, alternative is sigaction(3)
	signal( SIGFPE, sigfpe_handler );

	if( pthread_create( & thread, NULL, threadfn_exception, NULL ) )
	{
		ERROR;
		return -1;
	}
	if( pthread_join( thread, NULL ) )
	{
		ERROR;
		return -2;
	}
	printf("Done!\n");
	return 0;
}

c#学习笔记——进程(process)与线程(thread)

c#学习笔记——进程(process)与线程(thread)

一、进程

1、进程类是指 Process 类,该类所在的命名空间是 System.Diagnostics。快捷键应用:alt+shift+f10

2、进程是操作系统资源分配的基本单位。每一个应用程序都是进程。

3、在获取当前操作系统中运行的进程时,如果要获取所有运行的进程的信息可以使用 GetProcesses() 方法

来打开电脑中的应用程序 如:qq、微信、计算器等等

4、需要注意的是,一些进程由于权限不够是无法关闭的,因此在关闭进程的代码中要做异常处理。

 

5、Process 类的常用属性和方法如下表所示。

 

属性或方法 说明
MachineName 属性,获取关联进程正在其上运行的计算机的名称
Id 属性,获取关联进程的唯一标识符
ExitTime 属性,获取关联进程退出的时间
ProcessName 属性,获取该进程的名称
StartTime 属性,获取关联进程启动的时间
Threads 属性,获取在关联进程中运行的一组线程
TotalProcessorTime 属性,获取此进程的总的处理器时间
UserProcessorTime 属性,获取此进程的用户处理器时间
Close() 方法,释放与此组件关联的所有资源
CloseMainWindow() 方法,通过向进程的主窗口发送关闭消息来关闭拥有用户界面的进程
Dispose() 方法,释放由 Component 使用的所有资源
GetCurrentProcess() 方法,获取新的 Process 组件,并将其与当前活动的进程关联
GetProcesses() 方法,为本地计算机上的每个进程资源创建一个新的 Process 组件
GetProcesses(String) 方法,为指定计算机上的每个进程资源创建一个新的 Process 组件
GetProcessesByName(String) 方法,创建新的 Process 组件的数组,并将它们与本地计算机上共享指定的进程名称的所有进程资源关联
Kill() 方法,立即停止关联的进程
Start() 方法,启动(或重用)此 Process 组件的 Startinfo 属性指定的进程资源, 并将其与该组件关联
Start(String)

方法,通过指定文档或应用程序文件的名称来启动进程资源,并将资源与新的 Process 组件关联

 

 二、线程(Thread)

1、线程是任务调度和执行的基本单位

2、线程(Thread)是包含在进程中的,它位于 System.Threading 命名空间中。

3、包含关系: 进程由多个线程组成 ,没有线程的进程可以看做是单线程的。如果一个进程内有多个线程,则执行过程不是一条的,而是多条线(线程)共同完成;

线程是进程的一部分,所以线程被为轻权进程或者轻量级线程

4、线程分为前台线程和后台线程、

(1)前台线程:只有所有的前台线程都才能完成程序关闭

主线程;默认创建线程 是前台线程;需要用  th.IsBackground = true;//将线程设为后台线程
          

(2)后台线程;只要所有的前台线程结束,后台线程自动结束

5、Thread 类主要用于实现线程的创建以及执行,其常用的属性和方法如下表所示。

属性或方法 说明
Name 属性,获取或设置线程的名称
Priority 属性,获取或设置线程的优先级
ThreadState 属性,获取线程当前的状态
IsAlive  属性,获取当前线程是否处于启动状态
IsBackground 属性,获取或设置值,表示该线程是否为后台线程
CurrentThread 属性,获取当前正在运行的线程
Start()  方法,启动线程
Sleep(int millisecondsTimout) 方法,将当前线程暂停指定的毫秒数
Suspend() 方法,挂起当前线程(已经被弃用)
Join() 方法,阻塞调用线程,直到某个线程终止为止
Interrupt() 方法,中断当前线程
Resume() 方法,继续已经挂起的线程(已经被弃用)
Abort() 方法,终止线程

 

 

 

c++多线程编程之CreateThread与_beginthreadex本质区别

c++多线程编程之CreateThread与_beginthreadex本质区别

使用多线程其实是非常容易的,下面这个程序的主线程会创建了一个子线程并等待其运行完毕,子线程就输出它的线程ID号然后输出一句经典名言——Hello World。整个程序的代码非常简短,只有区区几行。

//最简单的创建多线程实例
#include <stdio.h>
#include <windows.h>
//子线程函数
DWORD WINAPI ThreadFun(LPVOID pM)
{
 printf("子线程的线程ID号为:%d\n子线程输出Hello World\n", GetCurrentThreadId());
 return 0;
}
//主函数,所谓主函数其实就是主线程执行的函数。
int main()
{
 printf("     最简单的创建多线程实例\n");
 printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
 HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL);
 WaitForSingleObject(handle, INFINITE);
 return 0;
}

下面来细讲下代码中的一些函数

第一个 CreateThread

函数功能:创建线程

函数原型:

HANDLEWINAPICreateThread(
  LPSECURITY_ATTRIBUTESlpThreadAttributes,
  SIZE_TdwStackSize,
  LPTHREAD_START_ROUTINElpStartAddress,
  LPVOIDlpParameter,
  DWORDdwCreationFlags,
  LPDWORDlpThreadId
);

函数说明:

第一个参数表示线程内核对象的安全属性,一般传入NULL表示使用默认设置。

第二个参数表示线程栈空间大小。传入0表示使用默认大小(1MB)。

第三个参数表示新线程所执行的线程函数地址,多个线程可以使用同一个函数地址。

第四个参数是传给线程函数的参数。

第五个参数指定额外的标志来控制线程的创建,为0表示线程创建之后立即就可以进行调度,如果为CREATE_SUSPENDED则表示线程创建后暂停运行,这样它就无法调度,直到调用ResumeThread()

第六个参数将返回线程的ID号,传入NULL表示不需要返回该线程ID号。

函数返回值:

成功返回新线程的句柄,失败返回NULL

第二个 WaitForSingleObject

函数功能:等待函数使线程进入等待状态,直到指定的内核对象被触发。

函数原形:

DWORDWINAPIWaitForSingleObject(
  HANDLEhHandle,
  DWORDdwMilliseconds
);

函数说明:

第一个参数为要等待的内核对象。

第二个参数为最长等待的时间,以毫秒为单位,如传入5000就表示5秒,传入0就立即返回,传入INFINITE表示无限等待。

因为线程的句柄在线程运行时是未触发的,线程结束运行,句柄处于触发状态。所以可以用WaitForSingleObject()来等待一个线程结束运行。

函数返回值:

在指定的时间内对象被触发,函数返回WAIT_OBJECT_0。超过最长等待时间对象仍未被触发返回WAIT_TIMEOUT。传入参数有错误将返回WAIT_FAILED

CreateThread()函数是Windows提供的API接口,在C/C++语言另有一个创建线程的函数_beginthreadex(),在很多书上(包括《Windows核心编程》)提到过尽量使用_beginthreadex()来代替使用CreateThread(),这是为什么了?下面就来探索与发现它们的区别吧。

      首先要从标准C运行库与多线程的矛盾说起,标准C运行库在1970年被实现了,由于当时没任何一个操作系统提供对多线程的支持。因此编写标准C运行库的程序员根本没考虑多线程程序使用标准C运行库的情况。比如标准C运行库的全局变量errno。很多运行库中的函数在出错时会将错误代号赋值给这个全局变量,这样可以方便调试。但如果有这样的一个代码片段:

if (system("notepad.exe readme.txt") == -1)

{

 switch(errno)

 {

  ...//错误处理代码

 }

}

假设某个线程A在执行上面的代码,该线程在调用system()之后且尚未调用switch()语句时另外一个线程B启动了,这个线程B也调用了标准C运行库的函数,不幸的是这个函数执行出错了并将错误代号写入全局变量errno中。这样线程A一旦开始执行switch()语句时,它将访问一个被B线程改动了的errno。这种情况必须要加以避免!因为不单单是这一个变量会出问题,其它像strerror()strtok()tmpnam()gmtime()asctime()等函数也会遇到这种由多个线程访问修改导致的数据覆盖问题。

为了解决这个问题,Windows操作系统提供了这样的一种解决方案——每个线程都将拥有自己专用的一块内存区域来供标准C运行库中所有有需要的函数使用。而且这块内存区域的创建就是由C/C++运行库函数_beginthreadex()来负责的。下面列出_beginthreadex()函数的源代码(我在这份代码中增加了一些注释)以便读者更好的理解_beginthreadex()函数与CreateThread()函数的区别。

//_beginthreadex源码整理By MoreWindows( http://blog.csdn.net/MoreWindows )
_MCRTIMP uintptr_t __cdecl _beginthreadex(
 void *security,
 unsigned stacksize,
 unsigned (__CLR_OR_STD_CALL * initialcode) (void *),
 void * argument,
 unsigned createflag,
 unsigned *thrdaddr
)
{
 _ptiddata ptd;          //pointer to per-thread data 见注1
 uintptr_t thdl;         //thread handle 线程句柄
 unsigned long err = 0L; //Return from GetLastError()
 unsigned dummyid;    //dummy returned thread ID 线程ID号
 
 // validation section 检查initialcode是否为NULL
 _VALIDATE_RETURN(initialcode != NULL, EINVAL, 0);
 //Initialize FlsGetValue function pointer
 __set_flsgetvalue();
 
 //Allocate and initialize a per-thread data structure for the to-be-created thread.
 //相当于new一个_tiddata结构,并赋给_ptiddata指针。
 if ( (ptd = (_ptiddata)_calloc_crt(1, sizeof(struct _tiddata))) == NULL )
  goto error_return;
 // Initialize the per-thread data
 //初始化线程的_tiddata块即CRT数据区域 见注2
 _initptd(ptd, _getptd()->ptlocinfo);
 
 //设置_tiddata结构中的其它数据,这样这块_tiddata块就与线程联系在一起了。
 ptd->_initaddr = (void *) initialcode; //线程函数地址
 ptd->_initarg = argument;              //传入的线程参数
 ptd->_thandle = (uintptr_t)(-1);
 
#if defined (_M_CEE) || defined (MRTDLL)
 if(!_getdomain(&(ptd->__initDomain))) //见注3
 {
  goto error_return;
 }
#endif  // defined (_M_CEE) || defined (MRTDLL)
 
 // Make sure non-NULL thrdaddr is passed to CreateThread
 if ( thrdaddr == NULL )//判断是否需要返回线程ID号
  thrdaddr = &dummyid;
 // Create the new thread using the parameters supplied by the caller.
 //_beginthreadex()最终还是会调用CreateThread()来向系统申请创建线程
 if ( (thdl = (uintptr_t)CreateThread(
     (LPSECURITY_ATTRIBUTES)security,
     stacksize,
     _threadstartex,
     (LPVOID)ptd,
     createflag,
     (LPDWORD)thrdaddr))
  == (uintptr_t)0 )
 {
  err = GetLastError();
  goto error_return;
 }
 //Good return
 return(thdl); //线程创建成功,返回新线程的句柄.
 
 //Error return
error_return:
 //Either ptd is NULL, or it points to the no-longer-necessary block
 //calloc-ed for the _tiddata struct which should now be freed up.
 //回收由_calloc_crt()申请的_tiddata块
 _free_crt(ptd);
 // Map the error, if necessary.
 // Note: this routine returns 0 for failure, just like the Win32
 // API CreateThread, but _beginthread() returns -1 for failure.
 //校正错误代号(可以调用GetLastError()得到错误代号)
 if ( err != 0L )
  _dosmaperr(err);
 return( (uintptr_t)0 ); //返回值为NULL的效句柄
}

讲解下部分代码:

1_ptiddataptd;中的_ptiddata是个结构体指针。在mtdll.h文件被定义:

     typedefstruct_tiddata * _ptiddata

微软对它的注释为Structure for each thread''s data这是一个非常大的结构体,有很多成员。本文由于篇幅所限就不列出来了。

2_initptd(ptd, _getptd()->ptlocinfo);微软对这一句代码中的getptd()的说明为:

     /* return address of per-thread CRT data */

     _ptiddata __cdecl_getptd(void);

_initptd()说明如下:

     /* initialize a per-thread CRT data block */

     void__cdecl_initptd(_Inout_ _ptiddata _Ptd,_In_opt_ pthreadlocinfo _Locale);

注释中的CRT C Runtime Library)即标准C运行库。

3if(!_getdomain(&(ptd->__initDomain)))中的_getdomain()函数代码可以在thread.c文件中找到,其主要功能是初始化COM环境。

由上面的源代码可知,_beginthreadex()函数在创建新线程时会分配并初始化一个_tiddata块。这个_tiddata块自然是用来存放一些需要线程独享的数据。事实上新线程运行时会首先将_tiddata块与自己进一步关联起来。然后新线程调用标准C运行库函数如strtok()时就会先取得_tiddata块的地址再将需要保护的数据存入_tiddata块中。这样每个线程就只会访问和修改自己的数据而不会去篡改其它线程的数据了。因此,如果在代码中有使用标准C运行库中的函数时,尽量使用_beginthreadex()来代替CreateThread()相信阅读到这里时,你会对这句简短的话有个非常深刻的印象,如果有面试官问起,你也可以流畅准确的回答了^_^

接下来,类似于上面的程序用CreateThread()创建输出“Hello World”的子线程,下面使用_beginthreadex()来创建多个子线程:

//创建多子个线程实例

#include <stdio.h>

#include <process.h>

#include <windows.h>

//子线程函数

unsigned int __stdcall ThreadFun(PVOID pM)

{

 printf("线程ID号为%4d的子线程说:Hello World\n", GetCurrentThreadId());

 return 0;

}

//主函数,所谓主函数其实就是主线程执行的函数。

int main()

{

 printf("     创建多个子线程实例 \n");

 printf(" -- by MoreWindows( 
http://blog.csdn.net/MoreWindows
 ) --\n\n");

 

 const int THREAD_NUM = 5;

 HANDLE handle[THREAD_NUM];

 for (int i = 0; i < THREAD_NUM; i++)

  handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);

 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);

 return 0;

}

图中每个子线程说的都是同一句话,不太好看。能不能来一个线程报数功能,即第一个子线程输出1,第二个子线程输出2,第三个子线程输出3,……。要实现这个功能似乎非常简单——每个子线程对一个全局变量进行递增并输出就可以了。代码如下:

//子线程报数
#include <stdio.h>
#include <process.h>
#include <windows.h>
int g_nCount;
//子线程函数
unsigned int __stdcall ThreadFun(PVOID pM)
{
 g_nCount++;
 printf("线程ID号为%4d的子线程报数%d\n", GetCurrentThreadId(), g_nCount);
 return 0;
}
//主函数,所谓主函数其实就是主线程执行的函数。
int main()
{
 printf("     子线程报数 \n");
 printf(" -- by MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n");
 
 const int THREAD_NUM = 10;
 HANDLE handle[THREAD_NUM];
 g_nCount = 0;
 for (int i = 0; i < THREAD_NUM; i++)
  handle[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadFun, NULL, 0, NULL);
 WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
 return 0;
}

 

 

Delphi Thread 多线程编程(6)

Delphi Thread 多线程编程(6)

总结

以上是小编为你收集整理的Delphi Thread 多线程编程(6)全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

Delphi Thread线程编程(4)

Delphi Thread线程编程(4)

总结

以上是小编为你收集整理的Delphi Thread线程编程(4)全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

关于pthread编程3——线程除法溢出的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于c#学习笔记——进程(process)与线程(thread)、c++多线程编程之CreateThread与_beginthreadex本质区别、Delphi Thread 多线程编程(6)、Delphi Thread线程编程(4)等相关内容,可以在本站寻找。

本文标签: