| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Системное программирование и WinAPI > Отличие функций CreateThread и |
| Автор: Royan 3.4.2005, 20:24 |
| Всем привет. Такой вопрос, в чем отличие функций CreateThread и _beginthread/_beginthreadex? Спасибо |
| Автор: chipset 3.4.2005, 20:31 |
| CreateThread - чисто Win32Api'шная функция. _beginthread - функция библиотеки CRT, кроссплатформенна. |
| Автор: Royan 3.4.2005, 21:08 | ||
Бааа, то есть это что в каком-то стандарте написано... А какие функции синхронизации кросплатформенны? |
| Автор: NiJazz 3.4.2005, 21:18 |
| Да нет таких вроде. sleep если только. А ты два-то вопроса в один топик не гони, а то модер рассердится. |
| Автор: chipset 3.4.2005, 21:34 | ||||||
Угу. C-runtime Library
Ты про мьютексы и т.д.? Не знаю чтоб в CRT было такого, загляни http://boost.org. Да и вообще..
.. а то я ещё рычать, кусаться и драться рогами умею. |
| Автор: Royan 3.4.2005, 22:03 |
| Okey, boost boost'омон пока не стандарт, потому не считается. Вобщем всем спасибо, разница ясна |
| Автор: Nastya 4.4.2005, 09:43 |
| Это хорошо и долго описывается у Рихтера. но в кратце CreateThread - чисто Win32Api'шная функция, а вот _beginthread - функция библиотеки CRT, НЕ кроссплатформенна, но приспособленна для работы с С, т.е. она делает дополнительные манипуляции, что бы стандартные библиотеки корректно работатли (+ вызывает CreateThread ) . В общем если пишешь на С, то лучше пользоваться вторым. И ЧИТАТЬ РИХТЕРА |
| Автор: Fire-Plug 10.4.2005, 09:15 | ||
Абсолютно, верно, Настя, т.к. Рихтер в статье CreateThread vs. _beginthread очень подробно описывает почему _beginthread предпочтительнее. Она создает Thread Local Storage (TLS), где переопределены, в частности, все глобальные константы, к-рые ф-ции CRT-библиотеки юзают. Например, такая как errno. Именно TLS - гарантия, что ф-ции CRT-библиотеки будут работать корректно. Добавлено @ 09:17 Сорри, ошибка: не _beginthread, а _beginthreadex |
| Автор: Fire-Plug 10.4.2005, 09:29 | ||
глобальные константы ==> глобальные переменные ЗЫ: Пора завязывать - две ошибки подряд... |
| Автор: Cr@$h 10.4.2005, 14:14 |
| Привожу инфу не на родном языке. Просто меня так учили... Основные идеи я выделил. The previous section explained how to create a thread, unless you happen to be using the C runtime library ( which you are, for these exercises ). The C runtime library was delivered in a UNIX context, in which there is no distinction between processes and threads. In the Windows context, many threads can be executing in a single address space. All threads have access to all information in the address space – after all, that is very meaning of “executing in an address space”. On the positive side, this means that is easy for threads to share information with one another by writing into the process’s variables ( those that are not allocated in some thread’s stack ). On the negative side, this means that every variable that is not in stack can be read or written by every thread, even if the variable might have information that is relevant only to one of the threads. We can provide an excellent example of such variable, errno. If you have never used errno, think of it as a global variable that is set by a runtime function if there happened to be an error on the call. This is analogous to the value returned by GetLastError() in Win32 API. In the UNIX context, there is no function call to get the last eror; the process thread simply reads errno. As long as there is only one thread executing the process – this is the only way UNIX processes can be defined – this works fine. But in Windows, a race condition can arise as follows. Suppose there are two threads, R and S, executing in a process, and both decide to call C runtime functions concurrently. This means that on a uniprocessor system, either R or S, say R, will call the function and return. For this example, suppose that R”s call resulted in an error and that errno got set to reflect the nature of the error ( that is, R should check errno as soon as it has detected that its call failed ). Now suppose that the thread scheduler interrupts R just after it returns but before it checks errno. The scheduler then dispatches S, and S calls its runtime routine. The call S made also fails, so the runtime package sets errno to let S know the nature of the error, overwriting the previous value that R would have read if it had not been interrupted. S detects the call error and reads errno without a problem. Eventually R is given the processor and resumes execution. The first thing it does is check errno, and it will see the result from S’s call rather than from its own call. This situation will happen only under certain situations, so the error it produces will be sporadic and extremely difficult to find. How can this problem be avoided? Microsoft has provided an alternative function to CreateThread, called _beginthreadex, to be used with the programs that use multiple threads at the same time they use the C runtime library. The problem occurs with any globally accessible variable used by this library ( there are several of them ). The Microsoft solution is to have the C runtime library provide a copy of each of these variables for each thread. Then, when a thread interacts with the runtime library, variables are shared only between the runtime code and the thread, not among all threads. The _beginthreadex function creates the copy for a thread in conjunction with an embedded call to CreateThread. The details of _beginthreadex follow, beginning with its function prototype. unsigned _beginthreadex( void *security, unsigned stack_size, unsigned (_stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr ); Despite the apparent differences between the types of the parameters to _beginthreadex and those for CreateThread, you can declare the parameters described for CreateThread and pass them to _beginthreadex. This means we can translate the example CreateThread call described previously and program it as follows. FWORD WINAPI myFunc(LPVOID); LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL; DWORD stackSize = 0; Int theArg; DWORD dwCreationFlags = 0; DWPRD targetThreadID; … _beginthreadex( ( void * ) lpThredAttributes, ( unsigned ) stackSize, ( unsigned ( _stdcall * )( void * )) myFunc, ( void * ) &theArg, ( unsigned ) dwCreationFlags, ( unsigned * ) &targetThreadID ); This is ugly, but it works. You can make it look better with judicious use of macros. Before your code this up and try to compile it, be sure to see additional related remarks in the Lab Environment section of this exercise. |